--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/lib3gp/impl/src/atom.cpp Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,8900 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <3gplibrary/mp4config.h>
+#include <3gplibrary/mp4lib.h>
+#include "mp4atom.h"
+#include "mp4memwrap.h"
+#include "mp4buffer.h"
+#include "mp4endian.h"
+#include "mp4file.h"
+#include "mp4utils.h"
+
+// MACROS
+// Debug print macro
+#ifdef _DEBUG
+#include <e32svr.h>
+//#define PRINT(x) RDebug::Print x
+#define PRINT(x)
+#else
+#define PRINT(x)
+#endif
+
+mp4_i32 readBoxHeader(MP4HandleImp handle, mp4_i64* size, mp4_u32* type);
+
+/*
+ * Function:
+ *
+ * mp4_i32 metaDataAvailable(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ * This function determines whether meta data is available for reading
+ * or not.
+ *
+ * Meta data is available if the input is in a file.
+ *
+ * When reading from a stream, meta data is considered available if
+ * it is in the beginning of the stream and the entire Moov atom has
+ * been received. FTYP atom is allowed before MOOV atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ *
+ * Return value:
+ *
+ * 0 Meta data is not available because enough data has not
+ * been inserted into the library
+ * 1 Meta data is available
+ * Negative value Meta data is not available because of fatal error
+ *
+ */
+mp4_i32 metaDataAvailable(MP4HandleImp handle)
+{
+ mp4_u32 size;
+ mp4_u32 type;
+
+
+ /* Meta data is available if the input is in a file or if a complete file has been inputted as a stream*/
+
+ if (handle->file)
+ return 1;
+
+ /* When reading from a stream, meta data is considered available if
+ it is in the beginning of the stream and the entire MOOV atom has
+ been received. FTYP atom is allowed before MOOV atom. */
+
+ if (!handle->ftypRead)
+ {
+ if (peekData(handle, handle->buf, 8) < 0) /* 8 bytes are not available */
+ return 0;
+
+ size = u32endian(*((mp4_u32 *)handle->buf));
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ if (type == ATOMTYPE_FTYP)
+ {
+ if (getBufferedBytes(handle) - handle->position < size) /* FTYP is not available */
+ return 0;
+ if ((handle->ftyp = (fileTypeAtom *)mp4malloc(sizeof(fileTypeAtom))) == NULL)
+ return -100;
+ if (readFTYP(handle, handle->ftyp) < 0)
+ return -2;
+ }
+ }
+
+ // Now the ftyp is read. No need to chedk MOOV presence for full files in the memory.
+ if (handle->LastWriteDataCalled == MP4TRUE)
+ return 1;
+
+ if (handle->LastWriteDataCalled == MP4FALSE)
+ {//Whole stream is not fed to the internal memory yet.
+ for (;;)
+ {
+ if (peekData(handle, handle->buf, 8) < 0)
+ return 0;
+
+ size = u32endian(*((mp4_u32 *)handle->buf));
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ if (type == ATOMTYPE_MOOV)
+ {
+ if (getBufferedBytes(handle) - handle->absPosition >= size) /* Entire Moov is available */
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ if ((mp4_i32)size <= 0)
+ return -1;
+
+ handle->absPosition+=size;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readFTYP(MP4HandleImp handle,
+ * fileTypeAtom *ftyp)
+ *
+ * Description:
+ *
+ * This function parses one FTYP atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * ftyp FTYP pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readFTYP(MP4HandleImp handle, fileTypeAtom *ftyp)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+ mp4_u32 n = 0;
+ mp4_i32 compatiblebrandsize = 0;
+
+
+ if ((ftyp->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, ftyp->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (ftyp->atomhdr->type != ATOMTYPE_FTYP)
+ return -1;
+
+ if (ftyp->atomhdr->size < 16) // 8(header)+8bytes needed for major and minor brand
+ return -1;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ ftyp->majorBrand = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ ftyp->minorVersion = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ if (ftyp->atomhdr->size == (mp4_u32)totalbytesread)
+ return totalbytesread;
+
+ compatiblebrandsize = (mp4_i32)ftyp->atomhdr->size - totalbytesread;
+ if ( compatiblebrandsize < 4 ) // at this point we must have at least 1 compatible brand
+ return -1;
+ if ( compatiblebrandsize > 20*4) // maximum of 20 compatible brands 4byte entries
+ return -1;
+ if ( compatiblebrandsize % 4 ) // must be able to divide by 4
+ return -1;
+
+ ftyp->compatibleBrands = (mp4_u32 *)mp4malloc( compatiblebrandsize );
+ if (ftyp->compatibleBrands == NULL)
+ return -1;
+
+ while ((mp4_u32)totalbytesread < ftyp->atomhdr->size)
+ {
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+
+ ftyp->compatibleBrands[n] = u32endian(*((mp4_u32 *)handle->buf));
+
+ n++;
+ totalbytesread += bytesread;
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readMetaData(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ * This function reads the meta data from the file/stream and stores
+ * the information in the atom structures available via handle.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ *
+ * Return value:
+ *
+ * Negative value Error
+ * >= 0 Success. Value tells the number of bytes read.
+ *
+ */
+mp4_i32 readMetaData(MP4HandleImp handle)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if (handle->file)
+ {
+ mp4_u64 size;
+ mp4_u32 type;
+
+
+ if (seekFileAbs(handle, 0) < 0)
+ return -1;
+
+ /* Seek to the start of FTYP atom */
+
+ for (;;)
+ {
+ if (readBoxHeader(handle, &size, &type) <0)
+ return -1;
+
+ if (type == ATOMTYPE_FTYP)
+ {
+ /* Read FTYP */
+
+ if ((handle->ftyp = (fileTypeAtom *)mp4malloc(sizeof(fileTypeAtom))) == NULL)
+ return -100;
+ bytesread = readFTYP(handle, handle->ftyp);
+ if (bytesread < 0)
+ return -3;
+ totalbytesread += bytesread;
+
+ break;
+ }
+
+ if (size <= 0)
+ return -1;
+
+ if (seekFile(handle, size) != 0)
+ return -1;
+ }
+
+ if (seekFileAbs(handle, 0) < 0)
+ return -1;
+
+ /* Seek to the start of MOOV atom */
+ for (;;)
+ {
+ if (readBoxHeader(handle, &size, &type) <0)
+ return -1;
+
+ if (type == ATOMTYPE_MOOV)
+ break;
+
+ if (size <= 0)
+ return -1;
+
+ if (seekFile(handle, size) != 0)
+ return -1;
+ }
+ }
+
+ // If all data of a file is in the memory and the file does not have MOOV box right after FTYP,
+ // then we need to seek for the location of the MOOV first
+
+ if (handle->LastWriteDataCalled == MP4TRUE)
+ {
+ mp4_u32 size;
+ mp4_u32 type;
+ // Seek until the beginning of MOOV box.
+ for(;;)
+ {
+ if (peekData(handle, handle->buf, 8) < 0)
+ return -1;
+
+ size = u32endian(*((mp4_u32 *)handle->buf));
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ if (type == ATOMTYPE_MOOV)
+ break;
+
+ if ((mp4_i32)size <= 0)
+ return -1;
+
+ if (discardData(handle, size) < 0)
+ return -1;
+ }
+ }
+
+ if ((handle->moov = (movieAtom *)mp4malloc(sizeof(movieAtom))) == NULL)
+ return -100;
+
+ bytesread = readMoov(handle, handle->moov);
+ if (bytesread < 0)
+ return -3;
+ totalbytesread += bytesread;
+
+ if (handle->moov->trakAudio)
+ {
+ mp4_u32 audiotype;
+ mp4_i32 errorAudio = 0;
+
+ errorAudio = determineAudioType(handle, &audiotype);
+ if ( errorAudio == 0 )
+ {
+ handle->type |= audiotype;
+
+ /* Move to the beginning of the 1st audio frame */
+ switch (advanceAudioSample(handle, handle->moov->trakAudio))
+ {
+ case -1:
+ return -1;
+ case -2:
+ handle->audioLast = MP4TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (errorAudio == -2)
+ {
+ handle->type |= audiotype;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ if (handle->moov->trakVideo)
+ {
+ mp4_u32 videotype;
+ mp4_i32 errorVideo = 0;
+
+ errorVideo = determineVideoType(handle, &videotype);
+ if ( errorVideo == 0 )
+ {
+ handle->type |= videotype;
+
+ /* Move to the beginning of the 1st video frame */
+ switch (advanceVideoFrame(handle, handle->moov->trakVideo))
+ {
+ case -1:
+ return -1;
+ case -2:
+ handle->videoLast = MP4TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (errorVideo == -2)
+ {
+ handle->type |= videotype;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readMoov(MP4HandleImp handle,
+ * movieAtom *moov)
+ *
+ * Description:
+ *
+ * This function parses one MOOV atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * moov MOOV pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMoov(MP4HandleImp handle, movieAtom *moov)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((moov->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, moov->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (moov->atomhdr->type != ATOMTYPE_MOOV)
+ return -1;
+
+ while ((mp4_u32)totalbytesread < handle->moov->atomhdr->size)
+ {
+ mp4_u32 type;
+
+
+ if (peekData(handle, handle->buf, 8) < 0)
+ return -1;
+
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ switch (type)
+ {
+ case ATOMTYPE_MVHD:
+
+ if (moov->mvhd) /* MVHD has already been read, more than one is not allowed */
+ return -1;
+
+ if ((moov->mvhd = (movieHeaderAtom *)mp4malloc(sizeof(movieHeaderAtom))) == NULL)
+ return -100;
+
+ bytesread = readMVHD(handle, moov->mvhd);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_IODS:
+
+ if (moov->iods) /* IODS has already been read, more than one is not allowed */
+ return -1;
+
+ if ((moov->iods = (objectDescriptorAtom *)mp4malloc(sizeof(objectDescriptorAtom))) == NULL)
+ return -100;
+
+ bytesread = readIODS(handle, moov->iods);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_TRAK:
+
+ {
+ trackAtom *ta;
+
+ if ((ta = (trackAtom *)mp4malloc(sizeof(trackAtom))) == NULL)
+ return -100;
+
+ bytesread = readTRAK(handle, ta);
+ if (bytesread < 0)
+ {
+ if (freeTRAK(ta) < 0)
+ return -1;
+ return -1;
+ }
+ totalbytesread += bytesread;
+
+ if (!ta->mdia)
+ {
+ if (freeTRAK(ta) < 0)
+ return -1;
+ return -1;
+ }
+ if (!ta->mdia->hdlr)
+ {
+ if (freeTRAK(ta) < 0)
+ return -1;
+ return -1;
+ }
+
+ if (ta->mdia->hdlr->handlerType != HANDLERTYPE_VIDE &&
+ ta->mdia->hdlr->handlerType != HANDLERTYPE_SOUN) /* Track is neither video nor audio */
+ {
+ /* Do nothing with the unknown track */
+ if (freeTRAK(ta) < 0)
+ return -1;
+ break;
+ }
+
+ if (ta->mdia->hdlr->handlerType == HANDLERTYPE_VIDE)
+ {
+ if (moov->trakVideo) /* Video Track already read */
+ {
+ if (freeTRAK(ta) < 0)
+ return -1;
+ }
+ else
+ {
+ moov->trakVideo = ta;
+ }
+ }
+ else if (ta->mdia->hdlr->handlerType == HANDLERTYPE_SOUN)
+ {
+ if (moov->trakAudio) /* Audio Track already read */
+ {
+ if (freeTRAK(ta) < 0)
+ return -1;
+ }
+ else
+ {
+ moov->trakAudio = ta;
+ }
+ }
+ else
+ {
+ }
+ break;
+ }
+
+ case ATOMTYPE_UDTA:
+
+ {
+ if (moov->udta) /* UDTA has already been read */
+ {
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+ break;
+ }
+
+
+ if ((moov->udta = (userDataAtom *)mp4malloc(sizeof(userDataAtom))) == NULL)
+ return -100;
+
+ bytesread = readUDTA(handle, moov->udta);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+ }
+
+ default:
+
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+ }
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readAtomheader(MP4HandleImp handle,
+ * atomHeader *ah)
+ *
+ * Description:
+ *
+ * This function reads an atom header and stores the information
+ * in ah.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * ah atomHeader structure that is used to store the
+ * information
+ *
+ * Return value:
+ *
+ * Negative value Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readAtomHeader(MP4HandleImp handle, atomHeader *ah)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+ //PRINT((_L("readAtomHeader")));
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ ah->size = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ ah->type = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ if (ah->size == 1)
+ {
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+ ah->largeSize = u64endian(*((mp4_u64 *)handle->buf));
+ totalbytesread += bytesread;
+ }
+
+ if (ah->type == ATOMTYPE_UUID)
+ {
+ bytesread = readData(handle, handle->buf, 16);
+ if (bytesread < 0)
+ return -1;
+ mp4memcpy(ah->extendedType, handle->buf, 16);
+ totalbytesread += bytesread;
+ }
+
+ //PRINT((_L(" size %u, size %Lu, type %c%c%c%c"), ah->size, ah->largeSize,((unsigned char *)(&ah->type))[3], ((unsigned char *)(&ah->type))[2], ((unsigned char *)(&ah->type))[1], ((unsigned char *)(&ah->type))[0]));
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readFullAtomHeader(MP4HandleImp handle,
+ * atomHeader *ah)
+ *
+ * Description:
+ *
+ * This function reads a full atom header and stores the information
+ * in ah.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * ah atomHeader structure that is used to store the
+ * information
+ *
+ * Return value:
+ *
+ * Negative value Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readFullAtomHeader(MP4HandleImp handle, atomHeader *ah)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+ //PRINT((_L("readFullAtomHeader")));
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ ah->size = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ ah->type = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ ah->version = *(handle->buf);
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 3);
+ if (bytesread < 0)
+ return -1;
+ mp4memcpy(ah->flags, handle->buf, 3);
+ totalbytesread += bytesread;
+
+ //PRINT((_L(" size %u, size %Lu, type %c%c%c%c"), ah->size, ah->largeSize,((unsigned char *)(&ah->type))[3], ((unsigned char *)(&ah->type))[2], ((unsigned char *)(&ah->type))[1], ((unsigned char *)(&ah->type))[0]));
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readMVHD(MP4HandleImp handle,
+ * movieHeaderAtom *mvhd)
+ *
+ * Description:
+ *
+ * This function parses one MVHD atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * mvhd MVHD pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMVHD(MP4HandleImp handle, movieHeaderAtom *mvhd)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((mvhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, mvhd->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (mvhd->atomhdr->type != ATOMTYPE_MVHD)
+ return -1;
+
+ if (mvhd->atomhdr->version == 1) /* 64 bit */
+ {
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+ mvhd->creationTime64 = u64endian(*((mp4_u64 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+ mvhd->modificationTime64 = u64endian(*((mp4_u64 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ mvhd->timeScale = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+ mvhd->duration64 = u64endian(*((mp4_u64 *)handle->buf));
+ totalbytesread += bytesread;
+ }
+ else /* 32 bit */
+ {
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ mvhd->creationTime = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ mvhd->modificationTime = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ mvhd->timeScale = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ mvhd->duration = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+ }
+
+ bytesread = discardData(handle, 76);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ mvhd->nextTrackID = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readIODS(MP4HandleImp handle,
+ * objectDescriptorAtom *iods)
+ *
+ * Description:
+ *
+ * This function parses one IODS atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * iods IODS pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readIODS(MP4HandleImp handle, objectDescriptorAtom *iods)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((iods->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, iods->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (iods->atomhdr->type != ATOMTYPE_IODS)
+ return -1;
+
+ bytesread = discardData(handle, iods->atomhdr->size - totalbytesread);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readTRAK(MP4HandleImp handle,
+ * trackAtom *trak)
+ *
+ * Description:
+ *
+ * This function parses one TRAK atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * trak TRAK pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readTRAK(MP4HandleImp handle, trackAtom *trak)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((trak->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, trak->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (trak->atomhdr->type != ATOMTYPE_TRAK)
+ return -1;
+
+
+ while ((mp4_u32)totalbytesread < trak->atomhdr->size)
+ {
+ mp4_u32 type;
+
+
+ if (peekData(handle, handle->buf, 8) < 0)
+ return -1;
+
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ switch (type)
+ {
+ case ATOMTYPE_TKHD:
+
+ if (trak->tkhd) /* MVHD has already been read, more than one is not allowed */
+ return -1;
+
+ if ((trak->tkhd = (trackHeaderAtom *)mp4malloc(sizeof(trackHeaderAtom))) == NULL)
+ return -100;
+
+ bytesread = readTKHD(handle, trak->tkhd);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_TREF:
+
+ if (trak->tref) /* TREF has already been read, more than one is not allowed */
+ return -1;
+
+ if ((trak->tref = (trackReferenceAtom *)mp4malloc(sizeof(trackReferenceAtom))) == NULL)
+ return -100;
+
+ bytesread = readTREF(handle, trak->tref);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_EDTS:
+
+ if (trak->edts) /* EDTS has already been read, more than one is not allowed */
+ return -1;
+
+ if ((trak->edts = (editListContainerAtom *)mp4malloc(sizeof(editListContainerAtom))) == NULL)
+ return -100;
+
+ bytesread = readEDTS(handle, trak->edts);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_MDIA:
+
+ if (trak->mdia) /* MDIA has already been read, more than one is not allowed */
+ return -1;
+
+ if ((trak->mdia = (mediaAtom *)mp4malloc(sizeof(mediaAtom))) == NULL)
+ return -100;
+
+ bytesread = readMDIA(handle, trak->mdia);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_UDTA:
+ {
+ if (trak->udta) /* UDTA has already been read */
+ {
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+ break;
+ }
+
+ if ((trak->udta = (userDataAtom *)mp4malloc(sizeof(userDataAtom))) == NULL)
+ return -100;
+
+ bytesread = readUDTA(handle, trak->udta);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+ }
+
+ default:
+
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+ }
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readUnknown(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ * This function reads one atom of unknown type. Atom contents are
+ * discarded.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readUnknown(MP4HandleImp handle)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+ mp4_u32 size;
+
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ size = u32endian(*((mp4_u32 *)handle->buf));
+ if ( size < 4 )
+ {
+ return -1;
+ }
+
+ if ( handle->file )
+ {
+ if ( seekFile(handle, size - totalbytesread) < 0 )
+ {
+ return -1;
+ }
+ else
+ {
+ return size;
+ }
+ }
+ else
+ {
+ bytesread = discardData(handle, size - totalbytesread);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+ }
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readTKHD(MP4HandleImp handle,
+ * trackHeaderAtom *tkhd)
+ *
+ * Description:
+ *
+ * This function parses one TKHD atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * tkhd TKHD pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readTKHD(MP4HandleImp handle, trackHeaderAtom *tkhd)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((tkhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, tkhd->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (tkhd->atomhdr->type != ATOMTYPE_TKHD)
+ return -1;
+
+ if (tkhd->atomhdr->version == 1) /* 64 bit */
+ {
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+ tkhd->creationTime64 = u64endian(*((mp4_u64 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+ tkhd->modificationTime64 = u64endian(*((mp4_u64 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ tkhd->trackID = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ tkhd->reserved = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+ tkhd->duration64 = u64endian(*((mp4_u64 *)handle->buf));
+ totalbytesread += bytesread;
+ }
+ else /* 32 bit */
+ {
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ tkhd->creationTime = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ tkhd->modificationTime = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ tkhd->trackID = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ tkhd->reserved = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ tkhd->duration = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+ }
+
+ bytesread = discardData(handle, 52);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ tkhd->width = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ tkhd->height = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readTREF(MP4HandleImp handle,
+ * trackReferenceAtom *tref)
+ *
+ * Description:
+ *
+ * This function parses one TREF atom and discards the contents.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * tref TREF pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readTREF(MP4HandleImp handle, trackReferenceAtom *tref)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((tref->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, tref->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (tref->atomhdr->type != ATOMTYPE_TREF)
+ return -1;
+
+ bytesread = discardData(handle, tref->atomhdr->size - totalbytesread);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readEDTS(MP4HandleImp handle,
+ * editListContainerAtom *edts)
+ *
+ * Description:
+ *
+ * This function parses one EDTS atom and discards the contents.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * edts EDTS pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readEDTS(MP4HandleImp handle, editListContainerAtom *edts)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((edts->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, edts->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (edts->atomhdr->type != ATOMTYPE_EDTS)
+ return -1;
+
+ bytesread = discardData(handle, edts->atomhdr->size - totalbytesread);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readMDIA(MP4HandleImp handle,
+ * mediaAtom *mdia)
+ *
+ * Description:
+ *
+ * This function parses one MDIA atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * mdia MDIA pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMDIA(MP4HandleImp handle, mediaAtom *mdia)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((mdia->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, mdia->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (mdia->atomhdr->type != ATOMTYPE_MDIA)
+ return -1;
+
+
+ while ((mp4_u32)totalbytesread < mdia->atomhdr->size)
+ {
+ mp4_u32 type;
+
+
+ if (peekData(handle, handle->buf, 8) < 0)
+ return -1;
+
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ switch (type)
+ {
+ case ATOMTYPE_MDHD:
+
+ if (mdia->mdhd) /* MDHD has already been read, more than one is not allowed */
+ return -1;
+
+ if ((mdia->mdhd = (mediaHeaderAtom *)mp4malloc(sizeof(mediaHeaderAtom))) == NULL)
+ return -100;
+
+ bytesread = readMDHD(handle, mdia->mdhd);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_HDLR:
+
+ if (mdia->hdlr) /* HDLR has already been read, more than one is not allowed */
+ return -1;
+
+ if ((mdia->hdlr = (handlerAtom *)mp4malloc(sizeof(handlerAtom))) == NULL)
+ return -100;
+
+ bytesread = readHDLR(handle, mdia->hdlr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_MINF:
+
+ if (mdia->minf) /* MINF has already been read, more than one is not allowed */
+ return -1;
+
+ if ((mdia->minf = (mediaInformationAtom *)mp4malloc(sizeof(mediaInformationAtom))) == NULL)
+ return -100;
+
+ bytesread = readMINF(handle, mdia->minf);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ default:
+
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+ }
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readMDHD(MP4HandleImp handle,
+ * mediaHeaderAtom *mdhd)
+ *
+ * Description:
+ *
+ * This function parses one MDHD atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * mdhd MDHD pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMDHD(MP4HandleImp handle, mediaHeaderAtom *mdhd)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((mdhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, mdhd->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (mdhd->atomhdr->type != ATOMTYPE_MDHD)
+ return -1;
+
+
+ if (mdhd->atomhdr->version == 1) /* 64 bit */
+ {
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+ mdhd->creationTime64 = u64endian(*((mp4_u64 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+ mdhd->modificationTime64 = u64endian(*((mp4_u64 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ mdhd->timeScale = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+ mdhd->duration64 = u64endian(*((mp4_u64 *)handle->buf));
+ totalbytesread += bytesread;
+ }
+ else /* 32 bit */
+ {
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ mdhd->creationTime = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ mdhd->modificationTime = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ mdhd->timeScale = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ mdhd->duration = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+ }
+
+ bytesread = discardData(handle, 4);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readHDLR(MP4HandleImp handle,
+ * handlerAtom *hdlr)
+ *
+ * Description:
+ *
+ * This function parses one HDLR atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * hdlr HDLR pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readHDLR(MP4HandleImp handle, handlerAtom *hdlr)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((hdlr->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, hdlr->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (hdlr->atomhdr->type != ATOMTYPE_HDLR)
+ return -1;
+
+
+ bytesread = discardData(handle, 4);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ hdlr->handlerType = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, hdlr->atomhdr->size - totalbytesread);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readMINF(MP4HandleImp handle,
+ * mediaInformationAtom *minf)
+ *
+ * Description:
+ *
+ * This function parses one MINF atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * minf MINF pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMINF(MP4HandleImp handle, mediaInformationAtom *minf)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((minf->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, minf->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (minf->atomhdr->type != ATOMTYPE_MINF)
+ return -1;
+
+
+ while ((mp4_u32)totalbytesread < minf->atomhdr->size)
+ {
+ mp4_u32 type;
+
+
+ if (peekData(handle, handle->buf, 8) < 0)
+ return -1;
+
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ switch (type)
+ {
+ case ATOMTYPE_VMHD:
+
+ if (minf->vmhd || minf->smhd) /* VMHD or SMHD has already been read, more than one is not allowed */
+ return -1;
+
+ if ((minf->vmhd = (videoMediaHeaderAtom *)mp4malloc(sizeof(videoMediaHeaderAtom))) == NULL)
+ return -100;
+
+ bytesread = readVMHD(handle, minf->vmhd);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_SMHD:
+
+ if (minf->smhd || minf->vmhd) /* SMHD or VMHD has already been read, more than one is not allowed */
+ return -1;
+
+ if ((minf->smhd = (soundMediaHeaderAtom *)mp4malloc(sizeof(soundMediaHeaderAtom))) == NULL)
+ return -100;
+
+ bytesread = readSMHD(handle, minf->smhd);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_DINF:
+
+ if (minf->dinf) /* DINF has already been read, more than one is not allowed */
+ return -1;
+
+ if ((minf->dinf = (dataInformationAtom *)mp4malloc(sizeof(dataInformationAtom))) == NULL)
+ return -100;
+
+ bytesread = readDINF(handle, minf->dinf);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_STBL:
+
+ if (minf->stbl) /* STBL has already been read, more than one is not allowed */
+ return -1;
+
+ if ((minf->stbl = (sampleTableAtom *)mp4malloc(sizeof(sampleTableAtom))) == NULL)
+ return -100;
+
+ bytesread = readSTBL(handle, minf->stbl);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ default:
+
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+ }
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readVMHD(MP4HandleImp handle,
+ * videoMediaHeaderAtom *vmhd)
+ *
+ * Description:
+ *
+ * This function parses one VMHD atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * vmhd VMHD pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readVMHD(MP4HandleImp handle, videoMediaHeaderAtom *vmhd)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((vmhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, vmhd->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (vmhd->atomhdr->type != ATOMTYPE_VMHD)
+ return -1;
+
+
+ bytesread = discardData(handle, vmhd->atomhdr->size - totalbytesread);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSMHD(MP4HandleImp handle,
+ * soundMediaHeaderAtom *smhd)
+ *
+ * Description:
+ *
+ * This function parses one SMHD atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * smhd SMHD pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSMHD(MP4HandleImp handle, soundMediaHeaderAtom *smhd)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((smhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, smhd->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (smhd->atomhdr->type != ATOMTYPE_SMHD)
+ return -1;
+
+
+ bytesread = discardData(handle, smhd->atomhdr->size - totalbytesread);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readDINF(MP4HandleImp handle,
+ * dataInformationAtom *dinf)
+ *
+ * Description:
+ *
+ * This function parses one DINF atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * dinf DINF pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readDINF(MP4HandleImp handle, dataInformationAtom *dinf)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((dinf->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, dinf->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (dinf->atomhdr->type != ATOMTYPE_DINF)
+ return -1;
+
+
+ while ((mp4_u32)totalbytesread < dinf->atomhdr->size)
+ {
+ mp4_u32 type;
+
+
+ if (peekData(handle, handle->buf, 8) < 0)
+ return -1;
+
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ switch (type)
+ {
+ case ATOMTYPE_DREF:
+
+ if (dinf->dref) /* DINF has already been read, more than one is not allowed */
+ return -1;
+
+ if ((dinf->dref = (dataReferenceAtom *)mp4malloc(sizeof(dataReferenceAtom))) == NULL)
+ return -100;
+
+ bytesread = readDREF(handle, dinf->dref);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ default:
+
+ return -1;
+ }
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readDREF(MP4HandleImp handle,
+ * dataReferenceAtom *dref)
+ *
+ * Description:
+ *
+ * This function parses one DREF atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * dref DREF pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readDREF(MP4HandleImp handle, dataReferenceAtom *dref)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((dref->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, dref->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (dref->atomhdr->type != ATOMTYPE_DREF)
+ return -1;
+
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ dref->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ if (dref->entryCount != 1)
+ return -1;
+
+ while ((mp4_u32)totalbytesread < dref->atomhdr->size)
+ {
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+ }
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readURL(MP4HandleImp handle,
+ * dataEntryURLAtom *url)
+ *
+ * Description:
+ *
+ * This function parses one URL atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * url URL pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readURL(MP4HandleImp handle, dataEntryURLAtom *url)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((url->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, url->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (url->atomhdr->type != ATOMTYPE_URL)
+ return -1;
+
+
+ if (!(url->atomhdr->flags[0] == 0x00 &&
+ url->atomhdr->flags[1] == 0x00 &&
+ url->atomhdr->flags[2] == 0x01))
+ return -1;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readURN(MP4HandleImp handle,
+ * dataEntryURNAtom *urn)
+ *
+ * Description:
+ *
+ * This function parses one URN atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * urn URN pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readURN(MP4HandleImp handle, dataEntryURNAtom *urn)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((urn->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, urn->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (urn->atomhdr->type != ATOMTYPE_URN)
+ return -1;
+
+
+ if (!(urn->atomhdr->flags[0] == 0x00 &&
+ urn->atomhdr->flags[1] == 0x00 &&
+ urn->atomhdr->flags[2] == 0x01))
+ return -1;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSTBL(MP4HandleImp handle,
+ * sampleTableAtom *stbl)
+ *
+ * Description:
+ *
+ * This function parses one STBL atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stbl STBL pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTBL(MP4HandleImp handle, sampleTableAtom *stbl)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((stbl->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, stbl->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (stbl->atomhdr->type != ATOMTYPE_STBL)
+ return -1;
+
+
+ while ((mp4_u32)totalbytesread < stbl->atomhdr->size)
+ {
+ mp4_u32 type;
+
+
+ if (peekData(handle, handle->buf, 8) < 0)
+ return -1;
+
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ switch (type)
+ {
+ case ATOMTYPE_STTS:
+
+ if (stbl->stts) /* STTS has already been read, more than one is not allowed */
+ return -1;
+
+ if ((stbl->stts = (timeToSampleAtom *)mp4malloc(sizeof(timeToSampleAtom))) == NULL)
+ return -100;
+
+ bytesread = readSTTS(handle, stbl->stts);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_CTTS:
+
+ if (stbl->ctts) /* CTTS has already been read, more than one is not allowed */
+ return -1;
+
+ if ((stbl->ctts = (compositionTimeToSampleAtom *)mp4malloc(sizeof(compositionTimeToSampleAtom))) == NULL)
+ return -100;
+
+ bytesread = readCTTS(handle, stbl->ctts);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_STSS:
+
+ if (stbl->stss) /* STSS has already been read, more than one is not allowed */
+ return -1;
+
+ if ((stbl->stss = (syncSampleAtom *)mp4malloc(sizeof(syncSampleAtom))) == NULL)
+ return -100;
+
+ bytesread = readSTSS(handle, stbl->stss);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_STSD:
+
+ if (stbl->stsd) /* STSD has already been read, more than one is not allowed */
+ return -1;
+
+ if ((stbl->stsd = (sampleDescriptionAtom *)mp4malloc(sizeof(sampleDescriptionAtom))) == NULL)
+ return -100;
+
+ bytesread = readSTSD(handle, stbl->stsd);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_STSZ:
+
+ if (stbl->stsz) /* STSZ or STZ2 has already been read, more than one is not allowed */
+ return -1;
+
+ if ((stbl->stsz = (sampleSizeAtom *)mp4malloc(sizeof(sampleSizeAtom))) == NULL)
+ return -100;
+
+ bytesread = readSTSZ(handle, stbl->stsz);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_STZ2:
+
+ if (stbl->stsz) /* STSZ or STZ2 has already been read, more than one is not allowed */
+ return -1;
+
+ if ((stbl->stsz = (sampleSizeAtom *)mp4malloc(sizeof(sampleSizeAtom))) == NULL)
+ return -100;
+
+ bytesread = readSTZ2(handle, stbl->stsz);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_STSC:
+
+ if (stbl->stsc) /* STSC has already been read, more than one is not allowed */
+ return -1;
+
+ if ((stbl->stsc = (sampleToChunkAtom *)mp4malloc(sizeof(sampleToChunkAtom))) == NULL)
+ return -100;
+
+ bytesread = readSTSC(handle, stbl->stsc);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_STCO:
+
+ if (stbl->stco) /* STCO or CO64 has already been read, more than one is not allowed */
+ return -1;
+
+ if ((stbl->stco = (chunkOffsetAtom *)mp4malloc(sizeof(chunkOffsetAtom))) == NULL)
+ return -100;
+
+ stbl->is32BitOffsets = ETrue;
+ bytesread = readSTCO(handle, stbl->stco);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_CO64:
+
+ if (stbl->stco64) /* STCO or CO64 has already been read, more than one is not allowed */
+ return -1;
+
+ if ((stbl->stco64 = (chunkOffset64Atom *)mp4malloc(sizeof(chunkOffset64Atom))) == NULL)
+ return -100;
+
+ stbl->is32BitOffsets = EFalse;
+ bytesread = readCO64(handle, stbl->stco64);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ case ATOMTYPE_SDTP:
+ if (stbl->sdtp) /* SDTP has already been read, more than one is not allowed */
+ return -1;
+
+ if ((stbl->sdtp = (sampleDependencyAtom *)mp4malloc(sizeof(sampleDependencyAtom))) == NULL)
+ return -100;
+
+ if (!stbl->stsz)
+ {
+ return -1;
+ }
+
+ // sample_count of SDTP is taken from the sample_count in the Sample Size Box ('stsz') or
+ // Compact Sample Size Box (‘stz2’).
+ bytesread = readSDTP(handle, stbl->sdtp, stbl->stsz->sampleCount);
+
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+ break;
+
+ default: /* Other atoms are not needed */
+
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+ }
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSTTS(MP4HandleImp handle,
+ * timeToSampleAtom *stts)
+ *
+ * Description:
+ *
+ * This function parses one STTS atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stts STTS pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTTS(MP4HandleImp handle, timeToSampleAtom *stts)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+ mp4_u32 i;
+
+
+ if ((stts->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, stts->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (stts->atomhdr->type != ATOMTYPE_STTS)
+ return -1;
+
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ stts->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ if ( stts->entryCount )
+ {
+ stts->sampleCount = (mp4_u32 *)mp4malloc(stts->entryCount * sizeof(mp4_u32));
+ if (stts->sampleCount == NULL)
+ return -1;
+ stts->sampleDelta = (mp4_i32 *)mp4malloc(stts->entryCount * sizeof(mp4_i32));
+ if (stts->sampleDelta == NULL)
+ return -1;
+
+ for (i = 0; i < stts->entryCount; i++)
+ {
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+
+ stts->sampleCount[i] = u32endian(*((mp4_u32 *)handle->buf));
+ stts->sampleDelta[i] = i32endian(*((mp4_i32 *)(handle->buf+4)));
+
+ totalbytesread += bytesread;
+ }
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readCTTS(MP4HandleImp handle,
+ * compositionTimeToSampleAtom *ctts)
+ *
+ * Description:
+ *
+ * This function parses one CTTS atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * ctts CTTS pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readCTTS(MP4HandleImp handle, compositionTimeToSampleAtom *ctts)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+ mp4_u32 i;
+
+
+ if ((ctts->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, ctts->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (ctts->atomhdr->type != ATOMTYPE_CTTS)
+ return -1;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ ctts->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ if ( ctts->entryCount )
+ {
+ ctts->sampleCount = (mp4_u32 *)mp4malloc(ctts->entryCount * sizeof(mp4_u32));
+ if (ctts->sampleCount == NULL)
+ return -1;
+ ctts->sampleOffset = (mp4_u32 *)mp4malloc(ctts->entryCount * sizeof(mp4_u32));
+ if (ctts->sampleOffset == NULL)
+ return -1;
+
+ for (i = 0; i < ctts->entryCount; i++)
+ {
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+
+ ctts->sampleCount[i] = u32endian(*((mp4_u32 *)handle->buf));
+ ctts->sampleOffset[i] = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ totalbytesread += bytesread;
+ }
+ }
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSTSS(MP4HandleImp handle,
+ * syncSampleAtom *stss)
+ *
+ * Description:
+ *
+ * This function parses one STSS atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stss STSS pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTSS(MP4HandleImp handle, syncSampleAtom *stss)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+ mp4_u32 i;
+
+
+ if ((stss->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, stss->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (stss->atomhdr->type != ATOMTYPE_STSS)
+ return -1;
+
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ stss->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ if ( stss->entryCount )
+ {
+ stss->sampleNumber = (mp4_u32 *)mp4malloc(stss->entryCount * sizeof(mp4_u32));
+ if (stss->sampleNumber == NULL)
+ return -1;
+
+ for (i = 0; i < stss->entryCount; i++)
+ {
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+
+ stss->sampleNumber[i] = u32endian(*((mp4_u32 *)handle->buf));
+
+ totalbytesread += bytesread;
+ }
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSTSD(MP4HandleImp handle,
+ * sampleDescriptionAtom *stsd)
+ *
+ * Description:
+ *
+ * This function parses one STSD atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stsd STSD pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTSD(MP4HandleImp handle, sampleDescriptionAtom *stsd)
+ {
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+ mp4_u32 totalsampleentriesread = 0;
+ mp4_u32 unknownsampleentriesread = 0;
+ mp4_bool skipentries = 0;
+
+ if ((stsd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -100;
+ }
+
+ bytesread = readFullAtomHeader(handle, stsd->atomhdr);
+ if (bytesread < 0)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ totalbytesread += bytesread;
+
+ if (stsd->atomhdr->type != ATOMTYPE_STSD)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ stsd->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ mp4_u32 type;
+ while ((mp4_u32)totalbytesread < stsd->atomhdr->size)
+ {
+ // if the number of entries read already surpasses the number of entries specified
+ // within the STSD atom, the file is corrupted.
+ if ((totalsampleentriesread + unknownsampleentriesread) >= stsd->entryCount)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+
+ // read the next sample type
+ if (peekData(handle, handle->buf, 8) < 0)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ // if the max sample entiries supported by the library has been reached
+ if ((stsd->entryCount > STSDMAXSAMPLEENTRYCOUNT) && (totalsampleentriesread == STSDMAXSAMPLEENTRYCOUNT))
+ {
+ // skip reading the rest of the entries to make sure no more than max count of sample entries
+ // will be processed, so that cleanup will always work.
+ type = 0;
+ skipentries = 1;
+ }
+
+ switch (type)
+ {
+ case ATOMTYPE_MP4V:
+ {
+ if (stsd->mp4v[totalsampleentriesread]) /* MP4V[totalsampleentriesread] has already been read, more than one is not allowed */
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+
+ if ((stsd->mp4v[totalsampleentriesread] = (visualSampleEntry *)mp4malloc(sizeof(visualSampleEntry))) == NULL)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -100;
+ }
+
+ bytesread = readMP4V(handle, stsd->mp4v[totalsampleentriesread]);
+ totalsampleentriesread++;
+ if (bytesread < 0)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ totalbytesread += bytesread;
+ break;
+ }
+
+ case ATOMTYPE_MP4A:
+ {
+ if (stsd->mp4a[totalsampleentriesread]) /* MP4A[totalsampleentriesread] has already been read, more than one is not allowed */
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+
+ if ((stsd->mp4a[totalsampleentriesread] = (audioSampleEntry *)mp4malloc(sizeof(audioSampleEntry))) == NULL)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -100;
+ }
+
+ bytesread = readMP4A(handle, stsd->mp4a[totalsampleentriesread]);
+ totalsampleentriesread++;
+ if (bytesread < 0)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ totalbytesread += bytesread;
+ break;
+ }
+
+ case ATOMTYPE_MP4S:
+ {
+ if (stsd->mp4s[totalsampleentriesread]) /* MP4S has already been read, more than one is not allowed */
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+
+ if ((stsd->mp4s[totalsampleentriesread] = (mpegSampleEntry *)mp4malloc(sizeof(mpegSampleEntry))) == NULL)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -100;
+ }
+
+ bytesread = readMP4S(handle, stsd->mp4s[totalsampleentriesread]);
+ totalsampleentriesread++;
+ if (bytesread < 0)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+ break;
+
+ case ATOMTYPE_S263:
+ {
+ if (stsd->s263[totalsampleentriesread]) /* MP4S has already been read, more than one is not allowed */
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+
+ if ((stsd->s263[totalsampleentriesread] = (h263SampleEntry *)mp4malloc(sizeof(h263SampleEntry))) == NULL)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -100;
+ }
+
+ bytesread = readS263(handle, stsd->s263[totalsampleentriesread]);
+ totalsampleentriesread++;
+ if (bytesread < 0)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+ break;
+
+ case ATOMTYPE_SAMR:
+ {
+ if (stsd->samr[totalsampleentriesread]) /* SAMR has already been read, more than one is not allowed */
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+
+ if ((stsd->samr[totalsampleentriesread] = (amrSampleEntry *)mp4malloc(sizeof(amrSampleEntry))) == NULL)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -100;
+ }
+
+ bytesread = readSAMR(handle, stsd->samr[totalsampleentriesread]);
+ totalsampleentriesread++;
+ if (bytesread < 0)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+ break;
+
+ case ATOMTYPE_SAWB:
+ {
+ if (stsd->sawb[totalsampleentriesread]) /* SAWB has already been read, more than one is not allowed */
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+
+ if ((stsd->sawb[totalsampleentriesread] = (amrSampleEntry *)mp4malloc(sizeof(amrSampleEntry))) == NULL)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -100;
+ }
+
+ bytesread = readSAWB(handle, stsd->sawb[totalsampleentriesread]);
+ totalsampleentriesread++;
+ if (bytesread < 0)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+ break;
+
+ case ATOMTYPE_AVC1:
+ {
+ if (stsd->avc1[totalsampleentriesread]) /* AVC1 has already been read, more than one is not allowed */
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ if ((stsd->avc1[totalsampleentriesread] = (avcSampleEntry *)mp4malloc(sizeof(avcSampleEntry))) == NULL)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -100;
+ }
+
+ bytesread = readAVC1(handle, stsd->avc1[totalsampleentriesread]);
+ totalsampleentriesread++;
+ if (bytesread < 0)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+ break;
+
+ case ATOMTYPE_SQCP:
+ {
+ if (stsd->sqcp[totalsampleentriesread]) /* SQCP has already been read, more than one is not allowed */
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ if ((stsd->sqcp[totalsampleentriesread] = (qcelpSampleEntry *)mp4malloc(sizeof(qcelpSampleEntry))) == NULL)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -100;
+ }
+
+ bytesread = readSQCP(handle, stsd->sqcp[totalsampleentriesread]);
+ totalsampleentriesread++;
+ if (bytesread < 0)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+ break;
+
+ default: /* Other atoms are not needed */
+ // no need to increment totalsampleentriesread as no memory is allocated for unsupported
+ // or unrecognized sample types. Alternatively, increment the count of unknown samples.
+ // This is for ensure if a non-audio/video track can properly be parsed without being
+ // recongized as an invalid format file.
+ unknownsampleentriesread++;
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ totalbytesread += bytesread;
+ break;
+ }
+ }
+
+ // if the STSD atom's entry count is NOT the same as the number (supported & unsupported) entries parsed,
+ // the atom is likely a corrupted one.
+ if ((totalsampleentriesread + unknownsampleentriesread) != stsd->entryCount)
+ {
+ // for memory cleanup set entrycount to allocated num of entries.
+ stsd->entryCount = totalsampleentriesread;
+ return -1;
+ }
+ else
+ {
+ // if the STSD atom's entry count is the same as the number of (supported & unsupported) entries
+ // parsed, check if some entries are skipped because the max sample entry count has been reached
+ if (skipentries)
+ {
+ // if STSDMAXSAMPLEENTRYCOUNT was reached edit entrycount to make sure cleanup works.
+ stsd->entryCount = STSDMAXSAMPLEENTRYCOUNT;
+ }
+ else if (unknownsampleentriesread > 0)
+ {
+ // unknown (unsupported) sample entries present, set the STSD entry count to the actual
+ // number of supported sample entries detected
+ stsd->entryCount = totalsampleentriesread;
+ }
+ }
+
+ return totalbytesread;
+ }
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSTSZ(MP4HandleImp handle,
+ * sampleSizeAtom *stsz)
+ *
+ * Description:
+ *
+ * This function parses one STSZ atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stsz STSZ pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTSZ(MP4HandleImp handle, sampleSizeAtom *stsz)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((stsz->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, stsz->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (stsz->atomhdr->type != ATOMTYPE_STSZ)
+ return -1;
+
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ stsz->sampleSize = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ stsz->sampleCount = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ // zero size samplesize means samples have different sizes, and those sizes are stored in sampleSizeEntries.
+ if ((stsz->sampleCount) && (stsz->sampleSize == 0))
+ {
+ mp4_u32 i;
+
+ // check validity of stsz->sampleCount before allocating entrysize table.
+ if ( handle->moov->mvhd )
+ {
+ if ( handle->moov->mvhd->timeScale > 0 )
+ {
+ TUint magicNumberMaxSamplesInSec = MAXSAMPLESPERSECOND;
+ TUint maxSampleCount;
+
+ if ( handle->moov->mvhd->atomhdr->version == 1 ) // 64bit duration
+ {
+ maxSampleCount = I64INT(handle->moov->mvhd->duration64 / TUint(handle->moov->mvhd->timeScale) + 1) * magicNumberMaxSamplesInSec;
+ }
+ else // 32bit duration
+ {
+ maxSampleCount = TUint((TUint( handle->moov->mvhd->duration ) / TUint(handle->moov->mvhd->timeScale) + 1)) * magicNumberMaxSamplesInSec;
+ }
+
+ if ( maxSampleCount < stsz->sampleCount )
+ {
+ // corrupted
+ return -1;
+ }
+ }
+ }
+
+ // allocate stsz->entrySize table
+ stsz->entrySize = (mp4_u32 *)mp4malloc(stsz->sampleCount * sizeof(mp4_u32));
+ if (stsz->entrySize == NULL)
+ return -1;
+
+ for (i = 0; i < stsz->sampleCount; i++)
+ {
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+
+ stsz->entrySize[i] = u32endian(*((mp4_u32 *)handle->buf));
+
+ totalbytesread += bytesread;
+ }
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSTZ2(MP4HandleImp handle,
+ * sampleSizeAtom *stsz)
+ *
+ * Description:
+ *
+ * This function parses one STZ2 atom.
+ *
+ * The result is placed in STSZ structure.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stsz STSZ pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTZ2(MP4HandleImp handle, sampleSizeAtom *stsz)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+ mp4_u8 fieldsize;
+
+
+ if ((stsz->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, stsz->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (stsz->atomhdr->type != ATOMTYPE_STZ2)
+ return -1;
+
+
+ bytesread = discardData(handle, 3);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ fieldsize = handle->buf[0];
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ stsz->sampleCount = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ switch (fieldsize)
+ {
+ case 4: /* Two entries in each byte */
+
+ {
+ mp4_u32 i;
+
+ stsz->entrySize = (mp4_u32 *)mp4malloc(stsz->sampleCount * sizeof(mp4_u32));
+ if (stsz->entrySize == NULL)
+ return -1;
+
+ for (i = 0; i < (stsz->sampleCount + 1) / 2; i++)
+ {
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+
+ totalbytesread += bytesread;
+
+ stsz->entrySize[i * 2] = (mp4_u32)(handle->buf[0] >> 4);
+
+ if (stsz->sampleCount % 2 == 0) /* Even number of samples */
+ {
+ stsz->entrySize[i * 2 + 1] = (mp4_u32)(handle->buf[0] & 0x0f);
+ continue;
+ }
+
+ /* This condition is needed to avoid writing after the table */
+
+ if (i == (stsz->sampleCount + 1) / 2 - 1) /* Last sample */
+ {
+ }
+ else
+ stsz->entrySize[i * 2 + 1] = (mp4_u32)(handle->buf[0] & 0x0f);
+ }
+ }
+
+ break;
+
+ case 8: /* One entry for each byte */
+
+ {
+ mp4_u32 i;
+
+ stsz->entrySize = (mp4_u32 *)mp4malloc(stsz->sampleCount * sizeof(mp4_u32));
+ if (stsz->entrySize == NULL)
+ return -1;
+
+ for (i = 0; i < stsz->sampleCount; i++)
+ {
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+
+ stsz->entrySize[i] = (mp4_u32)handle->buf[0];
+
+ totalbytesread += bytesread;
+ }
+ }
+
+ break;
+
+ case 16: /* Each entry in 2 bytes */
+
+ {
+ mp4_u32 i;
+
+ stsz->entrySize = (mp4_u32 *)mp4malloc(stsz->sampleCount * sizeof(mp4_u32));
+ if (stsz->entrySize == NULL)
+ return -1;
+
+ for (i = 0; i < stsz->sampleCount; i++)
+ {
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+
+ stsz->entrySize[i] = (mp4_u32)u16endian(*((mp4_u16 *)handle->buf));
+
+ totalbytesread += bytesread;
+ }
+ }
+
+ break;
+
+ default: /* Illegal fieldsize */
+
+ return -1;
+ }
+
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSTSC(MP4HandleImp handle,
+ * sampleToChunkAtom *stsc)
+ *
+ * Description:
+ *
+ * This function parses one STSC atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stsc STSC pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTSC(MP4HandleImp handle, sampleToChunkAtom *stsc)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+ mp4_u32 i;
+
+
+ if ((stsc->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, stsc->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (stsc->atomhdr->type != ATOMTYPE_STSC)
+ return -1;
+
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ stsc->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ if (stsc->entryCount)
+ {
+ stsc->firstChunk = (mp4_u32 *)mp4malloc(stsc->entryCount * sizeof(mp4_u32));
+ if (stsc->firstChunk == NULL)
+ return -1;
+ stsc->samplesPerChunk = (mp4_u32 *)mp4malloc(stsc->entryCount * sizeof(mp4_u32));
+ if (stsc->samplesPerChunk == NULL)
+ return -1;
+ stsc->sampleDescriptionIndex = (mp4_u32 *)mp4malloc(stsc->entryCount * sizeof(mp4_u32));
+ if (stsc->sampleDescriptionIndex == NULL)
+ {
+ return -1;
+ }
+
+ for (i = 0; i < stsc->entryCount; i++)
+ {
+ bytesread = readData(handle, handle->buf, 12);
+ if (bytesread < 0)
+ return -1;
+
+ stsc->firstChunk[i] = u32endian(*((mp4_u32 *)handle->buf));
+ stsc->samplesPerChunk[i] = u32endian(*((mp4_u32 *)(handle->buf+4)));
+ stsc->sampleDescriptionIndex[i] = u32endian(*((mp4_u32 *)(handle->buf+8)));
+ if ( stsc->sampleDescriptionIndex[i] > stsc->entryCount)
+ {
+ return -1;
+ }
+
+ totalbytesread += bytesread;
+ }
+ }
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSTCO(MP4HandleImp handle,
+ * chunkOffsetAtom *stco)
+ *
+ * Description:
+ *
+ * This function parses one STCO atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stco STCO pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTCO(MP4HandleImp handle, chunkOffsetAtom *stco)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+ mp4_u32 i;
+
+
+ if ((stco->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, stco->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (stco->atomhdr->type != ATOMTYPE_STCO)
+ return -1;
+
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ stco->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ if (stco->entryCount)
+ {
+ // validate stco->entryCount before allocating chunkOffsetTable
+ if ( handle->moov->mvhd )
+ {
+ if ( handle->moov->mvhd->timeScale > 0 )
+ {
+ TUint magicNumberMaxSamplesInSec = MAXSAMPLESPERSECOND;
+ TUint maxSampleCount;
+
+ if ( handle->moov->mvhd->atomhdr->version == 1 ) // 64bit duration
+ {
+ maxSampleCount = I64INT(handle->moov->mvhd->duration64 / TUint(handle->moov->mvhd->timeScale) + 1) * magicNumberMaxSamplesInSec;
+ }
+ else // 32bit duration
+ {
+ maxSampleCount = TUint((TUint( handle->moov->mvhd->duration ) / TUint(handle->moov->mvhd->timeScale) + 1)) * magicNumberMaxSamplesInSec;
+ }
+
+ if ( maxSampleCount < stco->entryCount )
+ {
+ // corrupted
+ return -1;
+ }
+ }
+ }
+
+ stco->chunkOffset = (mp4_u32 *)mp4malloc(stco->entryCount * sizeof(mp4_u32));
+ if (stco->chunkOffset == NULL)
+ return -1;
+
+ for (i = 0; i < stco->entryCount; i++)
+ {
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+
+ stco->chunkOffset[i] = u32endian(*((mp4_u32 *)handle->buf));
+
+ totalbytesread += bytesread;
+ }
+ }
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readCO64(MP4HandleImp handle,
+ * chunkOffset64Atom *stco64)
+ *
+ * Description:
+ *
+ * This function parses one CO64 atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stco64 CO64 pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readCO64(MP4HandleImp handle, chunkOffset64Atom *stco64)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+ mp4_u32 i;
+
+
+ if ((stco64->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, stco64->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (stco64->atomhdr->type != ATOMTYPE_CO64)
+ return -1;
+
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ stco64->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ if ( stco64->entryCount )
+ {
+ stco64->chunkOffset = (mp4_u64 *)mp4malloc(stco64->entryCount * sizeof(mp4_u64));
+ if (stco64->chunkOffset == NULL)
+ return -1;
+
+ for (i = 0; i < stco64->entryCount; i++)
+ {
+ bytesread = readData(handle, handle->buf, 8);
+ if (bytesread < 0)
+ return -1;
+
+ stco64->chunkOffset[i] = u64endian(*((mp4_u64 *)(handle->buf)));
+
+ totalbytesread += bytesread;
+ }
+ }
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readMP4V(MP4HandleImp handle,
+ * visualSampleEntry *mp4v)
+ *
+ * Description:
+ *
+ * This function parses one MP4V atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * mp4v MP4V pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMP4V(MP4HandleImp handle, visualSampleEntry *mp4v)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((mp4v->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, mp4v->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (mp4v->atomhdr->type != ATOMTYPE_MP4V)
+ return -1;
+
+
+ bytesread = discardData(handle, 6);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ mp4v->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 16);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ mp4v->width = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ mp4v->height = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 50);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ((mp4v->esd = (ESDAtom *)mp4malloc(sizeof(ESDAtom))) == NULL)
+ return -100;
+
+ bytesread = readESD(handle, mp4v->esd);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ( totalbytesread < mp4v->atomhdr->size )
+ {
+ bytesread = discardData(handle, mp4v->atomhdr->size - totalbytesread );
+ if (bytesread < 0)
+ {
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readMP4A(MP4HandleImp handle,
+ * audioSampleEntry *mp4a)
+ *
+ * Description:
+ *
+ * This function parses one MP4A atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * mp4a MP4A pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMP4A(MP4HandleImp handle, audioSampleEntry *mp4a)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((mp4a->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, mp4a->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (mp4a->atomhdr->type != ATOMTYPE_MP4A)
+ return -1;
+
+
+ bytesread = discardData(handle, 6);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ mp4a->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 16);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ mp4a->timeScale = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 2);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ((mp4a->esd = (ESDAtom *)mp4malloc(sizeof(ESDAtom))) == NULL)
+ return -100;
+
+ bytesread = readESD(handle, mp4a->esd);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ( totalbytesread < mp4a->atomhdr->size )
+ {
+ bytesread = discardData(handle, mp4a->atomhdr->size - totalbytesread );
+ if (bytesread < 0)
+ {
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readMP4S(MP4HandleImp handle,
+ * mpegSampleEntry *mp4s)
+ *
+ * Description:
+ *
+ * This function parses one MP4S atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * mp4s MP4S pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMP4S(MP4HandleImp handle, mpegSampleEntry *mp4s)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((mp4s->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, mp4s->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (mp4s->atomhdr->type != ATOMTYPE_MP4S)
+ return -1;
+
+
+ bytesread = discardData(handle, 6);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ mp4s->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ if ((mp4s->esd = (ESDAtom *)mp4malloc(sizeof(ESDAtom))) == NULL)
+ return -100;
+
+ bytesread = readESD(handle, mp4s->esd);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ( totalbytesread < mp4s->atomhdr->size )
+ {
+ bytesread = discardData(handle, mp4s->atomhdr->size - totalbytesread );
+ if (bytesread < 0)
+ {
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readS263(MP4HandleImp handle,
+ * h263SampleEntry *s263)
+ *
+ * Description:
+ *
+ * This function parses one S263 atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * s263 S263 pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readS263(MP4HandleImp handle, h263SampleEntry *s263)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((s263->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, s263->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (s263->atomhdr->type != ATOMTYPE_S263)
+ return -1;
+
+
+ bytesread = discardData(handle, 6);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ s263->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 16);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ s263->width = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ s263->height = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 50);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ((s263->d263 = (h263SpecificAtom *)mp4malloc(sizeof(h263SpecificAtom))) == NULL)
+ return -100;
+
+ bytesread = readD263(handle, s263->d263);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ( totalbytesread < s263->atomhdr->size )
+ {
+ bytesread = discardData(handle, s263->atomhdr->size - totalbytesread );
+ if (bytesread < 0)
+ {
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSAMR(MP4HandleImp handle,
+ * amrSampleEntry *samr)
+ *
+ * Description:
+ *
+ * This function parses one SAMR atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * samr SAMR pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSAMR(MP4HandleImp handle, amrSampleEntry *samr)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((samr->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, samr->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (samr->atomhdr->type != ATOMTYPE_SAMR)
+ return -1;
+
+
+ bytesread = discardData(handle, 6);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ samr->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 16);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ samr->timeScale = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 2);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ((samr->damr = (amrDecSpecStruc *)mp4malloc(sizeof(amrDecSpecStruc))) == NULL)
+ return -100;
+
+ bytesread = readDAMR(handle, samr->damr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ( totalbytesread < samr->atomhdr->size )
+ {
+ bytesread = discardData(handle, samr->atomhdr->size - totalbytesread );
+ if (bytesread < 0)
+ {
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSAWB(MP4HandleImp handle,
+ * amrSampleEntry *sawb)
+ *
+ * Description:
+ *
+ * This function parses one SAWB atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * sawb SAWB pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSAWB(MP4HandleImp handle, amrSampleEntry *sawb)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((sawb->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, sawb->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (sawb->atomhdr->type != ATOMTYPE_SAWB)
+ return -1;
+
+
+ bytesread = discardData(handle, 6);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ sawb->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 16);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ sawb->timeScale = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 2);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ((sawb->damr = (amrDecSpecStruc *)mp4malloc(sizeof(amrDecSpecStruc))) == NULL)
+ return -100;
+
+ bytesread = readDAMR(handle, sawb->damr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ( totalbytesread < sawb->atomhdr->size )
+ {
+ bytesread = discardData(handle, sawb->atomhdr->size - totalbytesread );
+ if (bytesread < 0)
+ {
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readESD(MP4HandleImp handle,
+ * ESDAtom *esd)
+ *
+ * Description:
+ *
+ * This function parses one ESD atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * esd ESD pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readESD(MP4HandleImp handle, ESDAtom *esd)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+ mp4_i32 decConfDescrBytesRead = 0;
+
+
+ if ((esd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readFullAtomHeader(handle, esd->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (esd->atomhdr->type != ATOMTYPE_ESD)
+ return -1;
+
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ esd->esDescrTag = handle->buf[0];
+ totalbytesread += bytesread;
+ if (esd->esDescrTag != 3) /* ES_DescrTag == 3 */
+ return -1;
+
+ esd->size = 0;
+ do
+ {
+ mp4_u8 c;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ c = (mp4_u8)(handle->buf[0] & 0x7f);
+ esd->size = (esd->size << 7) | c;
+ totalbytesread += bytesread;
+ }
+ while (handle->buf[0] & 0x80);
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ esd->ESID = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ esd->flags = handle->buf[0];
+ totalbytesread += bytesread;
+
+ if (esd->flags & 0x80) /* Stream Dependence flag has been set */
+ {
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ esd->dependsOnESID = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+ }
+
+ if (esd->flags & 0x40) /* URL flag has been set */
+ {
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ esd->URLLength = handle->buf[0];
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, esd->URLLength);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+ }
+
+ if (esd->flags & 0x20) /* OCR stream flag has been set */
+ {
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ esd->OCRESID = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+ }
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ esd->decConfDescrTag = handle->buf[0];
+ totalbytesread += bytesread;
+ if (esd->decConfDescrTag != 4) /* DecoderConfigDescrTag == 4 */
+ return -1;
+
+ esd->decConfDescrSize = 0;
+ do
+ {
+ mp4_u8 c;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ c = (mp4_u8)(handle->buf[0] & 0x7f);
+ esd->decConfDescrSize = (esd->decConfDescrSize << 7) | c;
+ totalbytesread += bytesread;
+ }
+ while (handle->buf[0] & 0x80);
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ esd->objectTypeIndication = handle->buf[0];
+ totalbytesread += bytesread;
+ decConfDescrBytesRead += bytesread;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ esd->stream = handle->buf[0];
+ totalbytesread += bytesread;
+ decConfDescrBytesRead += bytesread;
+
+ bytesread = readData(handle, handle->buf, 3);
+ if (bytesread < 0)
+ return -1;
+ esd->bufferSizeDB = ((mp4_u32)handle->buf[0]) << 16 |
+ ((mp4_u32)handle->buf[1]) << 8 |
+ ((mp4_u32)handle->buf[2]);
+ totalbytesread += bytesread;
+ decConfDescrBytesRead += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ esd->maxBitrate = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+ decConfDescrBytesRead += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ esd->avgBitrate = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+ decConfDescrBytesRead += bytesread;
+
+ if ((mp4_u32)decConfDescrBytesRead < esd->decConfDescrSize)
+ {
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ esd->decSpecificInfoTag = handle->buf[0];
+ totalbytesread += bytesread;
+ decConfDescrBytesRead += bytesread;
+ if (esd->decSpecificInfoTag != 5) /* DecSpecificInfoTag == 5 */
+ {
+ bytesread = discardData(handle, esd->decConfDescrSize - decConfDescrBytesRead);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+ }
+ else
+ {
+ esd->decSpecificInfoSize = 0;
+ do
+ {
+ mp4_u8 c;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ c = (mp4_u8)(handle->buf[0] & 0x7f);
+ esd->decSpecificInfoSize = (esd->decSpecificInfoSize << 7) | c;
+ totalbytesread += bytesread;
+ }
+ while (handle->buf[0] & 0x80);
+
+ if(esd->decSpecificInfoSize)
+ {
+ if ((esd->decSpecificInfo = (mp4_u8 *)mp4malloc(esd->decSpecificInfoSize)) == NULL)
+ return -100;
+
+ bytesread = readData(handle, esd->decSpecificInfo, esd->decSpecificInfoSize);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+ }
+ }
+ }
+
+ bytesread = discardData(handle, esd->atomhdr->size - totalbytesread);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readD263(MP4HandleImp handle,
+ * h263SpecificAtom *d263)
+ *
+ * Description:
+ *
+ * This function parses one D263 atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * d263 D263 pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readD263(MP4HandleImp handle, h263SpecificAtom *d263)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((d263->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, d263->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (d263->atomhdr->type != ATOMTYPE_D263)
+ return -1;
+
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ d263->vendor = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ d263->decoderVersion = handle->buf[0];
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ d263->h263Level = handle->buf[0];
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ d263->h263Profile = handle->buf[0];
+ totalbytesread += bytesread;
+
+ /* Check for the bitrate atom */
+
+ while ((mp4_u32)totalbytesread < d263->atomhdr->size)
+ {
+ mp4_u32 type;
+
+
+ if (peekData(handle, handle->buf, 8) < 0)
+ return -1;
+
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ switch (type)
+ {
+ case ATOMTYPE_BITR:
+
+ if (d263->bitr) /* BITR has already been read, more than one is not allowed */
+ return -1;
+
+ if ((d263->bitr = (bitrateAtom *)mp4malloc(sizeof(bitrateAtom))) == NULL)
+ return -100;
+
+ bytesread = readBITR(handle, d263->bitr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ default: /* Other atoms are not needed */
+
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+ }
+ }
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readBITR(MP4HandleImp handle,
+ * bitrateAtom *d263)
+ *
+ * Description:
+ *
+ * This function parses one BITR atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * bitr BITR pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readBITR(MP4HandleImp handle, bitrateAtom *bitr)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((bitr->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, bitr->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (bitr->atomhdr->type != ATOMTYPE_BITR)
+ return -1;
+
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ bitr->avgBitrate = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ bitr->maxBitrate = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readDAMR(MP4HandleImp handle,
+ * amrDecSpecStruc *damr)
+ *
+ * Description:
+ *
+ * This function parses one DAMR atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * damr DAMR pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readDAMR(MP4HandleImp handle, amrDecSpecStruc *damr)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((damr->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, damr->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (damr->atomhdr->type != ATOMTYPE_DAMR)
+ return -1;
+
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ damr->vendor = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ damr->decoderVersion = handle->buf[0];
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ damr->modeSet = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ damr->modeChangePeriod = handle->buf[0];
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ damr->framesPerSample = handle->buf[0];
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeFTYP(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ * This function frees memory for FTYP atom.
+ *
+ * Parameters:
+ *
+ * ftyp FTYP atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeFTYP(fileTypeAtom *ftyp)
+{
+ if (ftyp)
+ {
+ if (freeAtomHeader(ftyp->atomhdr) < 0)
+ return -1;
+ if (ftyp->compatibleBrands)
+ mp4free(ftyp->compatibleBrands);
+
+ mp4free(ftyp);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeMOOV(movieAtom *moov)
+ *
+ * Description:
+ *
+ * This function frees memory for MOOV atom.
+ *
+ * Parameters:
+ *
+ * moov MOOV atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeMOOV(movieAtom *moov)
+{
+ if (moov)
+ {
+ if (freeAtomHeader(moov->atomhdr) < 0)
+ return -1;
+ if (freeMVHD(moov->mvhd) < 0)
+ return -1;
+ if (freeTRAK(moov->trakAudio) < 0)
+ return -1;
+ if (freeTRAK(moov->trakVideo) < 0)
+ return -1;
+ if (freeIODS(moov->iods) < 0)
+ return -1;
+ if (freeUDTA(moov->udta) < 0)
+ return -1;
+
+ mp4free(moov);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeAtomHeader(atomHeader *atomhdr)
+ *
+ * Description:
+ *
+ * This function frees memory for atom header.
+ *
+ * Parameters:
+ *
+ * atomhdr atom header pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeAtomHeader(atomHeader *atomhdr)
+{
+ if (atomhdr)
+ mp4free(atomhdr);
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeMVHD(movieHeaderAtom *mvhd)
+ *
+ * Description:
+ *
+ * This function frees memory for MVHD atom.
+ *
+ * Parameters:
+ *
+ * mvhd MVHD atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeMVHD(movieHeaderAtom *mvhd)
+{
+ if (mvhd)
+ {
+ if (freeAtomHeader(mvhd->atomhdr) < 0)
+ return -1;
+
+ mp4free(mvhd);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeTRAK(trackAtom *trak)
+ *
+ * Description:
+ *
+ * This function frees memory for TRAK atom.
+ *
+ * Parameters:
+ *
+ * trak TRAK atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeTRAK(trackAtom *trak)
+{
+ if (trak)
+ {
+ if (freeAtomHeader(trak->atomhdr) < 0)
+ return -1;
+ if (freeTKHD(trak->tkhd) < 0)
+ return -1;
+ if (freeTREF(trak->tref) < 0)
+ return -1;
+ if (freeEDTS(trak->edts) < 0)
+ return -1;
+ if (freeMDIA(trak->mdia) < 0)
+ return -1;
+ if (freeUDTA(trak->udta) < 0)
+ return -1;
+
+ mp4free(trak);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeTKHD(trackHeaderAtom *tkhd)
+ *
+ * Description:
+ *
+ * This function frees memory for TKHD atom.
+ *
+ * Parameters:
+ *
+ * tkhd TKHD atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeTKHD(trackHeaderAtom *tkhd)
+{
+ if (tkhd)
+ {
+ if (freeAtomHeader(tkhd->atomhdr) < 0)
+ return -1;
+
+ mp4free(tkhd);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeTREF(trackReferenceAtom *tref)
+ *
+ * Description:
+ *
+ * This function frees memory for TREF atom.
+ *
+ * Parameters:
+ *
+ * tref TREF atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeTREF(trackReferenceAtom *tref)
+{
+ if (tref)
+ {
+ if (freeAtomHeader(tref->atomhdr) < 0)
+ return -1;
+
+ mp4free(tref);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeEDTS(editListContainerAtom *edts)
+ *
+ * Description:
+ *
+ * This function frees memory for EDTS atom.
+ *
+ * Parameters:
+ *
+ * edts EDTS atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeEDTS(editListContainerAtom *edts)
+{
+ if (edts)
+ {
+ if (freeAtomHeader(edts->atomhdr) < 0)
+ return -1;
+
+ mp4free(edts);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeMDIA(mediaAtom *mdia)
+ *
+ * Description:
+ *
+ * This function frees memory for MDIA atom.
+ *
+ * Parameters:
+ *
+ * mdia MDIA atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeMDIA(mediaAtom *mdia)
+{
+ if (mdia)
+ {
+ if (freeAtomHeader(mdia->atomhdr) < 0)
+ return -1;
+ if (freeMDHD(mdia->mdhd) < 0)
+ return -1;
+ if (freeHDLR(mdia->hdlr) < 0)
+ return -1;
+ if (freeMINF(mdia->minf) < 0)
+ return -1;
+
+ mp4free(mdia);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeMDHD(mediaHeaderAtom *mdhd)
+ *
+ * Description:
+ *
+ * This function frees memory for MDHD atom.
+ *
+ * Parameters:
+ *
+ * mdhd MDHD atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeMDHD(mediaHeaderAtom *mdhd)
+{
+ if (mdhd)
+ {
+ if (freeAtomHeader(mdhd->atomhdr) < 0)
+ return -1;
+
+ mp4free(mdhd);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeHDLR(handlerAtom *hdlr)
+ *
+ * Description:
+ *
+ * This function frees memory for HDLR atom.
+ *
+ * Parameters:
+ *
+ * hdlr HDLR atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeHDLR(handlerAtom *hdlr)
+{
+ if (hdlr)
+ {
+ if (freeAtomHeader(hdlr->atomhdr) < 0)
+ return -1;
+ if (hdlr->name)
+ mp4free(hdlr->name);
+
+ mp4free(hdlr);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeMINF(mediaInformationAtom *minf)
+ *
+ * Description:
+ *
+ * This function frees memory for MINF atom.
+ *
+ * Parameters:
+ *
+ * minf MINF atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeMINF(mediaInformationAtom *minf)
+{
+ if (minf)
+ {
+ if (freeAtomHeader(minf->atomhdr) < 0)
+ return -1;
+ if (freeVMHD(minf->vmhd) < 0)
+ return -1;
+ if (freeSMHD(minf->smhd) < 0)
+ return -1;
+ if (freeDINF(minf->dinf) < 0)
+ return -1;
+ if (freeSTBL(minf->stbl) < 0)
+ return -1;
+
+ mp4free(minf);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeVMHD(videoMediaHeaderAtom *vmhd)
+ *
+ * Description:
+ *
+ * This function frees memory for VMHD atom.
+ *
+ * Parameters:
+ *
+ * vmhd VMHD atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeVMHD(videoMediaHeaderAtom *vmhd)
+{
+ if (vmhd)
+ {
+ if (freeAtomHeader(vmhd->atomhdr) < 0)
+ return -1;
+
+ mp4free(vmhd);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSMHD(soundMediaHeaderAtom *smhd)
+ *
+ * Description:
+ *
+ * This function frees memory for SMHD atom.
+ *
+ * Parameters:
+ *
+ * smhd SMHD atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSMHD(soundMediaHeaderAtom *smhd)
+{
+ if (smhd)
+ {
+ if (freeAtomHeader(smhd->atomhdr) < 0)
+ return -1;
+
+ mp4free(smhd);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeDINF(dataInformationAtom *dinf)
+ *
+ * Description:
+ *
+ * This function frees memory for DINF atom.
+ *
+ * Parameters:
+ *
+ * dinf DINF atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeDINF(dataInformationAtom *dinf)
+{
+ if (dinf)
+ {
+ if (freeAtomHeader(dinf->atomhdr) < 0)
+ return -1;
+ if (freeDREF(dinf->dref) < 0)
+ return -1;
+
+ mp4free(dinf);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeDREF(dataReferenceAtom *dref)
+ *
+ * Description:
+ *
+ * This function frees memory for DREF atom.
+ *
+ * Parameters:
+ *
+ * dref DREF atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeDREF(dataReferenceAtom *dref)
+{
+ if (dref)
+ {
+ if (freeAtomHeader(dref->atomhdr) < 0)
+ return -1;
+ if (freeURL(dref->url) < 0)
+ return -1;
+ if (freeURN(dref->urn) < 0)
+ return -1;
+
+ mp4free(dref);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeURL(dataEntryURLAtom *url)
+ *
+ * Description:
+ *
+ * This function frees memory for URL atom.
+ *
+ * Parameters:
+ *
+ * url URL atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeURL(dataEntryURLAtom *url)
+{
+ if (url)
+ {
+ if (freeAtomHeader(url->atomhdr) < 0)
+ return -1;
+
+ mp4free(url);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeURN(dataEntryURNAtom *urn)
+ *
+ * Description:
+ *
+ * This function frees memory for URN atom.
+ *
+ * Parameters:
+ *
+ * urn URN atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeURN(dataEntryURNAtom *urn)
+{
+ if (urn)
+ {
+ if (freeAtomHeader(urn->atomhdr) < 0)
+ return -1;
+
+ mp4free(urn);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSTBL(sampleTableAtom *stbl)
+ *
+ * Description:
+ *
+ * This function frees memory for STBL atom.
+ *
+ * Parameters:
+ *
+ * stbl STBL atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSTBL(sampleTableAtom *stbl)
+{
+ if (stbl)
+ {
+ if (freeAtomHeader(stbl->atomhdr) < 0)
+ return -1;
+ if (freeSTTS(stbl->stts) < 0)
+ return -1;
+ if (freeCTTS(stbl->ctts) < 0)
+ return -1;
+ if (freeSTSD(stbl->stsd) < 0)
+ return -1;
+ if (freeSTSZ(stbl->stsz) < 0)
+ return -1;
+ if (freeSTSC(stbl->stsc) < 0)
+ return -1;
+ if (stbl->is32BitOffsets)
+ {
+
+ if (freeSTCO(stbl->stco) < 0)
+ return -1;
+ }
+ else
+ {
+
+ if (freeSTCO64(stbl->stco64) < 0)
+ return -1;
+ }
+ if (freeSTSS(stbl->stss) < 0)
+ return -1;
+ if (freeSTSH(stbl->stsh) < 0)
+ return -1;
+ if (freeSDTP(stbl->sdtp) < 0)
+ return -1;
+
+ mp4free(stbl);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSTTS(timeToSampleAtom *stts)
+ *
+ * Description:
+ *
+ * This function frees memory for STTS atom.
+ *
+ * Parameters:
+ *
+ * stts STTS atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSTTS(timeToSampleAtom *stts)
+{
+ if (stts)
+ {
+ if (freeAtomHeader(stts->atomhdr) < 0)
+ return -1;
+ if (stts->sampleCount)
+ mp4free(stts->sampleCount);
+ if (stts->sampleDelta)
+ mp4free(stts->sampleDelta);
+
+ mp4free(stts);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeCTTS(compositionTimeToSampleAtom *ctts)
+ *
+ * Description:
+ *
+ * This function frees memory for CTTS atom.
+ *
+ * Parameters:
+ *
+ * ctts CTTS atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeCTTS(compositionTimeToSampleAtom *ctts)
+{
+ if (ctts)
+ {
+ if (freeAtomHeader(ctts->atomhdr) < 0)
+ return -1;
+ if (ctts->sampleCount)
+ mp4free(ctts->sampleCount);
+ if (ctts->sampleOffset)
+ mp4free(ctts->sampleOffset);
+
+ mp4free(ctts);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSTSD(sampleDescriptionAtom *stsd)
+ *
+ * Description:
+ *
+ * This function frees memory for STSD atom.
+ *
+ * Parameters:
+ *
+ * stsd STSD atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSTSD(sampleDescriptionAtom *stsd)
+{
+ mp4_u32 sampleentrycount = 0;
+ mp4_u32 entryindex;
+
+ if (stsd)
+ {
+ sampleentrycount = stsd->entryCount;
+
+ if (freeAtomHeader(stsd->atomhdr) < 0)
+ return -1;
+ for (entryindex = 0; entryindex < sampleentrycount; entryindex++)
+ {
+ if (freeMP4V(stsd->mp4v[entryindex]) < 0)
+ return -1;
+ if (freeMP4A(stsd->mp4a[entryindex]) < 0)
+ return -1;
+ if (freeMP4S(stsd->mp4s[entryindex]) < 0)
+ return -1;
+ if (freeS263(stsd->s263[entryindex]) < 0)
+ return -1;
+ if (freeSAMR(stsd->samr[entryindex]) < 0)
+ return -1;
+ if (freeSAWB(stsd->sawb[entryindex]) < 0)
+ return -1;
+ if (freeAVC1(stsd->avc1[entryindex]) < 0)
+ return -1;
+ if (freeSQCP(stsd->sqcp[entryindex]) < 0)
+ return -1;
+ }
+ mp4free(stsd);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeMP4V(visualSampleEntry *mp4v)
+ *
+ * Description:
+ *
+ * This function frees memory for MP4V atom.
+ *
+ * Parameters:
+ *
+ * mp4v MP4V atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeMP4V(visualSampleEntry *mp4v)
+{
+ if (mp4v)
+ {
+ if (freeAtomHeader(mp4v->atomhdr) < 0)
+ return -1;
+ if (freeESD(mp4v->esd) < 0)
+ return -1;
+
+ mp4free(mp4v);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeESD(ESDAtom *esd)
+ *
+ * Description:
+ *
+ * This function frees memory for ESD atom.
+ *
+ * Parameters:
+ *
+ * esd ESD atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeESD(ESDAtom *esd)
+{
+ if (esd)
+ {
+ if (freeAtomHeader(esd->atomhdr) < 0)
+ return -1;
+ if (esd->URLString)
+ mp4free(esd->URLString);
+ if (esd->decSpecificInfo)
+ mp4free(esd->decSpecificInfo);
+
+ mp4free(esd);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeMP4A(audioSampleEntry *mp4a)
+ *
+ * Description:
+ *
+ * This function frees memory for MP4A atom.
+ *
+ * Parameters:
+ *
+ * mp4a MP4A atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeMP4A(audioSampleEntry *mp4a)
+{
+ if (mp4a)
+ {
+ if (freeAtomHeader(mp4a->atomhdr) < 0)
+ return -1;
+ if (freeESD(mp4a->esd) < 0)
+ return -1;
+
+ mp4free(mp4a);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeMP4S(mpegSampleEntry *mp4s)
+ *
+ * Description:
+ *
+ * This function frees memory for MP4S atom.
+ *
+ * Parameters:
+ *
+ * mp4s MP4S atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeMP4S(mpegSampleEntry *mp4s)
+{
+ if (mp4s)
+ {
+ if (freeAtomHeader(mp4s->atomhdr) < 0)
+ return -1;
+ if (freeESD(mp4s->esd) < 0)
+ return -1;
+
+ mp4free(mp4s);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeS263(h263SampleEntry *s263)
+ *
+ * Description:
+ *
+ * This function frees memory for S263 atom.
+ *
+ * Parameters:
+ *
+ * s263 S263 atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeS263(h263SampleEntry *s263)
+{
+ if (s263)
+ {
+ if (freeAtomHeader(s263->atomhdr) < 0)
+ return -1;
+ if (freeD263(s263->d263) < 0)
+ return -1;
+
+ mp4free(s263);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeD263(h263SpecificAtom *d263)
+ *
+ * Description:
+ *
+ * This function frees memory for D263 atom.
+ *
+ * Parameters:
+ *
+ * d263 D263 atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeD263(h263SpecificAtom *d263)
+{
+ if (d263)
+ {
+ if (freeAtomHeader(d263->atomhdr) < 0)
+ return -1;
+ if (freeBITR(d263->bitr) < 0)
+ return -1;
+
+ mp4free(d263);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeBITR(BitrateAtom *bitr)
+ *
+ * Description:
+ *
+ * This function frees memory for BITR atom.
+ *
+ * Parameters:
+ *
+ * bitr BITR atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeBITR(bitrateAtom *bitr)
+{
+ if (bitr)
+ {
+ if (freeAtomHeader(bitr->atomhdr) < 0)
+ return -1;
+
+ mp4free(bitr);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSAMR(amrSampleEntry *samr)
+ *
+ * Description:
+ *
+ * This function frees memory for SAMR atom.
+ *
+ * Parameters:
+ *
+ * samr SAMR atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSAMR(amrSampleEntry *samr)
+{
+ if (samr)
+ {
+ if (freeAtomHeader(samr->atomhdr) < 0)
+ return -1;
+ if (freeDAMR(samr->damr) < 0)
+ return -1;
+
+ mp4free(samr);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSAWB(amrSampleEntry *sawb)
+ *
+ * Description:
+ *
+ * This function frees memory for SAWB atom.
+ *
+ * Parameters:
+ *
+ * sawb SAWB atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSAWB(amrSampleEntry *sawb)
+{
+ if (sawb)
+ {
+ if (freeAtomHeader(sawb->atomhdr) < 0)
+ return -1;
+ if (freeDAMR(sawb->damr) < 0)
+ return -1;
+
+ mp4free(sawb);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeDAMR(amrDecSpecStruc *damr)
+ *
+ * Description:
+ *
+ * This function frees memory for DAMR atom.
+ *
+ * Parameters:
+ *
+ * damr DAMR atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeDAMR(amrDecSpecStruc *damr)
+{
+ if (damr)
+ {
+ if (freeAtomHeader(damr->atomhdr) < 0)
+ return -1;
+
+ mp4free(damr);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSTSZ(sampleSizeAtom *stsz)
+ *
+ * Description:
+ *
+ * This function frees memory for STSZ atom.
+ *
+ * Parameters:
+ *
+ * stsz STSZ atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSTSZ(sampleSizeAtom *stsz)
+{
+ if (stsz)
+ {
+ if (freeAtomHeader(stsz->atomhdr) < 0)
+ return -1;
+ if (stsz->entrySize)
+ mp4free(stsz->entrySize);
+
+ mp4free(stsz);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSTSC(sampleToChunkAtom *stsc)
+ *
+ * Description:
+ *
+ * This function frees memory for STSC atom.
+ *
+ * Parameters:
+ *
+ * stsc STSC atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSTSC(sampleToChunkAtom *stsc)
+{
+ if (stsc)
+ {
+ if (freeAtomHeader(stsc->atomhdr) < 0)
+ return -1;
+ if (stsc->firstChunk)
+ mp4free(stsc->firstChunk);
+ if (stsc->samplesPerChunk)
+ mp4free(stsc->samplesPerChunk);
+ if (stsc->sampleDescriptionIndex)
+ mp4free(stsc->sampleDescriptionIndex);
+
+ mp4free(stsc);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSTCO(chunkOffsetAtom *stco)
+ *
+ * Description:
+ *
+ * This function frees memory for STCO atom.
+ *
+ * Parameters:
+ *
+ * stco STCO atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSTCO(chunkOffsetAtom *stco)
+{
+ if (stco)
+ {
+ if (freeAtomHeader(stco->atomhdr) < 0)
+ return -1;
+ if (stco->chunkOffset)
+ mp4free(stco->chunkOffset);
+
+ mp4free(stco);
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSTCO64(chunkOffset64Atom *stco64)
+ *
+ * Description:
+ *
+ * This function frees memory for STCO64 atom.
+ *
+ * Parameters:
+ *
+ * stco64 STCO64 atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSTCO64(chunkOffset64Atom *stco64)
+{
+ if (stco64)
+ {
+ if (freeAtomHeader(stco64->atomhdr) < 0)
+ return -1;
+ if (stco64->chunkOffset)
+ mp4free(stco64->chunkOffset);
+
+ mp4free(stco64);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSTSS(syncSampleAtom *stss)
+ *
+ * Description:
+ *
+ * This function frees memory for STSS atom.
+ *
+ * Parameters:
+ *
+ * stss STSS atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSTSS(syncSampleAtom *stss)
+{
+ if (stss)
+ {
+ if (freeAtomHeader(stss->atomhdr) < 0)
+ return -1;
+ if (stss->sampleNumber)
+ mp4free(stss->sampleNumber);
+
+ mp4free(stss);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSTSH(shadowSyncSampleAtom *stsh)
+ *
+ * Description:
+ *
+ * This function frees memory for STSH atom.
+ *
+ * Parameters:
+ *
+ * stsh STSH atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSTSH(shadowSyncSampleAtom *stsh)
+{
+ if (stsh)
+ {
+ if (freeAtomHeader(stsh->atomhdr) < 0)
+ return -1;
+
+ mp4free(stsh);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSDTP(sampleDependencyAtom *sdtp)
+ *
+ * Description:
+ *
+ * This function frees memory for SDTP atom.
+ *
+ * Parameters:
+ *
+ * sdtp SDTP atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSDTP(sampleDependencyAtom *sdtp)
+ {
+ if (sdtp)
+ {
+ if (freeAtomHeader(sdtp->atomhdr) < 0)
+ {
+ return -1;
+ }
+
+ if (sdtp->dep)
+ {
+ mp4free(sdtp->dep);
+ }
+
+ mp4free(sdtp);
+ }
+
+ return 0;
+ }
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeIODS(objectDescriptorAtom *iods)
+ *
+ * Description:
+ *
+ * This function frees memory for IODS atom.
+ *
+ * Parameters:
+ *
+ * iods IODS atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeIODS(objectDescriptorAtom *iods)
+{
+ if (iods)
+ {
+ if (freeAtomHeader(iods->atomhdr) < 0)
+ return -1;
+
+ mp4free(iods);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readUDTA(MP4HandleImp handle,
+ * userDataAtom *udta)
+ *
+ * Description:
+ *
+ * This function parses one UDTA atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * udta UDTA pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readUDTA(MP4HandleImp handle, userDataAtom *udta)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+ if ((udta->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, udta->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (udta->atomhdr->type != ATOMTYPE_UDTA)
+ return -1;
+
+ if ( handle->file )
+ {
+ udta->atomcontentloc = handle->diskReadBufStart + handle->diskReadBufPos;
+ }
+ else
+ {
+ udta->atomcontentloc = handle->absPosition;
+ }
+
+ if ( udta->atomhdr->size == 1 )
+ {
+ udta->atomcontentsize = I64INT(udta->atomhdr->largeSize) - (TInt)totalbytesread;
+ }
+ else
+ {
+ udta->atomcontentsize = (TInt)(udta->atomhdr->size - totalbytesread);
+ }
+
+ if ( handle->file )
+ {
+ if ( seekFile(handle, udta->atomhdr->size - totalbytesread) < 0 )
+ {
+ return -1;
+ }
+ else
+ {
+ return udta->atomhdr->size;
+ }
+ }
+ else
+ {
+ bytesread = discardData(handle, udta->atomhdr->size - totalbytesread);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+ }
+ return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeUDTA(userDataAtom *udta)
+ *
+ * Description:
+ *
+ * This function frees memory for UDTA atom.
+ *
+ * Parameters:
+ *
+ * udta UDTA atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeUDTA(userDataAtom *udta)
+{
+ if (udta)
+ {
+ if (freeAtomHeader(udta->atomhdr) < 0)
+ return -1;
+ mp4free(udta);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 determineVideoLength(MP4HandleImp handle,
+ * mp4_u32 *videolength)
+ *
+ * Description:
+ *
+ * This function determines the length of video in milliseconds.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * videolength Video length is returned here
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 determineVideoLength(MP4HandleImp handle, mp4_u32 *videolength)
+{
+ if (!handle->moov)
+ return -1;
+
+ if (!handle->moov->mvhd)
+ return -1;
+
+ if (!handle->moov->trakVideo)
+ return -1;
+
+ if (!handle->moov->trakVideo->tkhd)
+ return -1;
+
+ /* Is timescale set? */
+ if (handle->moov->mvhd->timeScale == 0)
+ return -1;
+
+ *videolength = (mp4_u32)(((mp4_double)handle->moov->trakVideo->tkhd->duration / (mp4_double)handle->moov->mvhd->timeScale) * (mp4_double)1000);
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 determineFrameRate(MP4HandleImp handle,
+ * mp4_double *framerate)
+ *
+ * Description:
+ *
+ * This function determines the frame rate of video.
+ *
+ * Frame rate is calculated as the average frame rate of the entire video.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * framerate Frame rate is returned here
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 determineFrameRate(MP4HandleImp handle, mp4_double *framerate)
+{
+ mp4_double numberofframes;
+ mp4_double length;
+
+
+ if (!handle)
+ return -1;
+ if (!handle->moov)
+ return -1;
+ if (!handle->moov->trakVideo)
+ return -1;
+ if (!handle->moov->trakVideo->mdia)
+ return -1;
+ if (!handle->moov->trakVideo->mdia->minf)
+ return -1;
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return -1;
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsz)
+ return -1;
+ if (!handle->moov->trakVideo->mdia->mdhd)
+ return -1;
+
+
+ if (handle->moov->trakVideo->mdia->mdhd->timeScale == 0)
+ return -1;
+
+ if (handle->moov->trakVideo->mdia->mdhd->duration == 0)
+ {
+ *framerate = 0;
+ }
+ else
+ {
+ numberofframes = (mp4_double)handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount;
+ length = (mp4_double)handle->moov->trakVideo->mdia->mdhd->duration /
+ (mp4_double)handle->moov->trakVideo->mdia->mdhd->timeScale;
+
+ *framerate = numberofframes / length;
+ }
+
+ return 0;
+ }
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 determineVideoType(MP4HandleImp handle,
+ * mp4_u32 *videotype)
+ *
+ * Description:
+ *
+ * This function determines the video type of the MP4.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * videotype Video type is returned here
+ *
+ * Return value:
+ *
+ * 0 Success
+ * -1 Error
+ * -2 Unknown video type
+ *
+ */
+mp4_i32 determineVideoType(MP4HandleImp handle, mp4_u32 *videotype)
+{
+ *videotype = MP4_TYPE_NONE;
+
+ if (!handle->moov)
+ return -1;
+
+ if (!handle->moov->trakVideo)
+ return -1;
+
+ if (!handle->moov->trakVideo->mdia)
+ return -1;
+
+ if (!handle->moov->trakVideo->mdia->minf)
+ return -1;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return -1;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd)
+ return -1;
+
+ if (handle->moov->trakVideo->mdia->minf->stbl->stsd->entryCount == 0)
+ return -1;
+
+/* Assume that the video type is the same for all sample entries. Just get the video type from the first one */
+
+ if (handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0])
+ {
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->esd)
+ return -1;
+
+ if ((handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->esd->objectTypeIndication == 0x20) &&
+ ((handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->esd->stream >> 2) == 0x04))
+ *videotype = MP4_TYPE_MPEG4_VIDEO;
+ }
+ else
+ if (handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0])
+ {
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->d263)
+ return -1;
+
+ switch (handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->d263->h263Profile)
+ {
+ case 0:
+ *videotype = MP4_TYPE_H263_PROFILE_0;
+ break;
+ case 3:
+ *videotype = MP4_TYPE_H263_PROFILE_3;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ if (handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0])
+ {
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc)
+ return -1;
+
+ if (handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfigSize == 0)
+ return -1;
+
+ /* AVC profile is in the second byte of the avcconfigrecord */
+ switch((mp4_u8)handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfig[1])
+ {
+ case 66:
+ *videotype = MP4_TYPE_AVC_PROFILE_BASELINE;
+ break;
+ case 77:
+ *videotype = MP4_TYPE_AVC_PROFILE_MAIN;
+ break;
+ case 88:
+ *videotype = MP4_TYPE_AVC_PROFILE_EXTENDED;
+ break;
+ case 100:
+ *videotype = MP4_TYPE_AVC_PROFILE_HIGH;
+ break;
+ default:
+ {
+ mp4_u8 constraintByte = (mp4_u8)handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfig[2];
+ if ( (constraintByte & 0x80) || (constraintByte & 0x10) )
+ {
+ *videotype = MP4_TYPE_AVC_PROFILE_BASELINE;
+ }
+ else if (constraintByte & 0x40)
+ {
+ *videotype = MP4_TYPE_AVC_PROFILE_MAIN;
+ }
+ else if (constraintByte & 0x20)
+ {
+ *videotype = MP4_TYPE_AVC_PROFILE_EXTENDED;
+ }
+ // NOTE: Cannot reliably determine higher profiles from
+ // the constraint flags.
+ break;
+ }
+ }
+ }
+ else
+ {}
+ /* Note: Read the AVC level and recreate the actual AVC profile and level in the future! */
+ if (*videotype == MP4_TYPE_NONE)
+ return -2;
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 determineVideoResolution(MP4HandleImp handle,
+ * mp4_u32 *videowidth,
+ * mp4_u32 *videoheight)
+ *
+ * Description:
+ *
+ * This function finds out the video width and height from the atom
+ * structure.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * videowidth Video width is returned here
+ * videoheight Video height is returned here
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 determineVideoResolution(MP4HandleImp handle, mp4_u32 *videowidth, mp4_u32 *videoheight)
+{
+ mp4_u32 videotype = MP4_TYPE_NONE;
+
+
+ if (determineVideoType(handle, &videotype) < 0)
+ return -1;
+
+ if (videotype == MP4_TYPE_NONE)
+ return -1;
+
+ if (!handle->moov)
+ return -1;
+
+ if (!handle->moov->trakVideo)
+ return -1;
+
+ if (!handle->moov->trakVideo->mdia)
+ return -1;
+
+ if (!handle->moov->trakVideo->mdia->minf)
+ return -1;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return -1;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd)
+ return -1;
+
+ if (handle->moov->trakVideo->mdia->minf->stbl->stsd->entryCount == 0)
+ return -1;
+
+/* Assume that the video characteristics for all the video sample entries are the same. Just get them from the first one */
+
+ if (videotype == MP4_TYPE_H263_PROFILE_0 ||
+ videotype == MP4_TYPE_H263_PROFILE_3)
+ {
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0])
+ return -1;
+
+ *videowidth = handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->width;
+ *videoheight = handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->height;
+ }
+ else if (videotype == MP4_TYPE_MPEG4_VIDEO)
+ {
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0])
+ return -1;
+
+ *videowidth = handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->width;
+ *videoheight = handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->height;
+ }
+ else if ( isAvcVideo(videotype) )
+ {
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0])
+ return -1;
+
+ *videowidth = handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->width;
+ *videoheight = handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->height;
+ }
+ else
+ {
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 determineVideoTimeScale(MP4HandleImp handle,
+ * mp4_u32 *timescale)
+ *
+ * Description:
+ *
+ * This function determines the timescale of video track.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * timescale Timescale of video track is returned here
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 determineVideoTimeScale(MP4HandleImp handle, mp4_u32 *timescale)
+{
+ if (timescale == NULL)
+ return 0;
+
+ if (!handle)
+ return -1;
+ if (!handle->moov)
+ return -1;
+ if (!handle->moov->trakVideo)
+ return -1;
+ if (!handle->moov->trakVideo->mdia)
+ return -1;
+ if (!handle->moov->trakVideo->mdia->mdhd)
+ return -1;
+ if (handle->moov->trakVideo->mdia->mdhd->timeScale == 0)
+ return -1;
+
+ *timescale = handle->moov->trakVideo->mdia->mdhd->timeScale;
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 determineAudioLength(MP4HandleImp handle,
+ * mp4_u32 *audiolength)
+ *
+ * Description:
+ *
+ * This function determines the length of audio in milliseconds.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * audiolength Audio length is returned here
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 determineAudioLength(MP4HandleImp handle, mp4_u32 *audiolength)
+{
+ if (!handle->moov)
+ return -1;
+
+ if (!handle->moov->mvhd)
+ return -1;
+
+ if (!handle->moov->trakAudio)
+ return -1;
+
+ if (!handle->moov->trakAudio->tkhd)
+ return -1;
+
+ /* Is timescale set? */
+ if (handle->moov->mvhd->timeScale == 0)
+ return -1;
+
+ *audiolength = (mp4_u32)(((mp4_double)handle->moov->trakAudio->tkhd->duration / (mp4_double)handle->moov->mvhd->timeScale) * (mp4_double)1000);
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 determineAudioType(MP4HandleImp handle,
+ * mp4_u32 *audiotype)
+ *
+ * Description:
+ *
+ * This function determines the audio type of the MP4.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * audiotype Audio type is returned here
+ *
+ * Return value:
+ *
+ * 0 Success
+ * -1 Error
+ * -2 Unknown audiotrack
+ *
+ */
+mp4_i32 determineAudioType(MP4HandleImp handle, mp4_u32 *audiotype)
+{
+ *audiotype = MP4_TYPE_NONE;
+
+
+ if (!handle->moov)
+ return -1;
+
+ if (!handle->moov->trakAudio)
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia)
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia->minf)
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl)
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd)
+ return -1;
+
+ if (handle->moov->trakAudio->mdia->minf->stbl->stsd->entryCount == 0)
+ return -1;
+
+/* Assume that the audio type is the same for all sample entries. Just get the audio type from the first one */
+ if (handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0])
+ {
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd)
+ return -1;
+
+ if ((handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd->objectTypeIndication == 0x40) &&
+ ((handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd->stream >> 2) == 0x05))
+ *audiotype = MP4_TYPE_MPEG4_AUDIO;
+
+ if ((handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd->objectTypeIndication == 0xE1) &&
+ ((handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd->stream >> 2) == 0x05))
+ {
+ *audiotype = MP4_TYPE_QCELP_13K;
+ handle->qcelpStoredAsMPEGAudio = MP4TRUE;
+ }
+ }
+ else if (handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[0])
+ *audiotype = MP4_TYPE_AMR_NB;
+ else if (handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[0])
+ *audiotype = MP4_TYPE_AMR_WB;
+ else if (handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[0])
+ {
+ *audiotype = MP4_TYPE_QCELP_13K;
+ handle->qcelpStoredAsMPEGAudio = MP4FALSE;
+ }
+ else
+ {
+ }
+
+ if (*audiotype == MP4_TYPE_NONE)
+ return -2;
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 determineAudioFramesPerSample(MP4HandleImp handle,
+ * mp4_u8 *framespersample)
+ *
+ * Description:
+ *
+ * This function determines the number of audio frames in each sample.
+ * The function works with AMR audio type only.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * framespersample Number of frames in each sample
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 determineAudioFramesPerSample(MP4HandleImp handle, mp4_u8 *framespersample)
+{
+ mp4_i8 sampleentryindex;
+
+ *framespersample = 0;
+
+
+ if (!((handle->type & MP4_TYPE_AMR_NB) ||
+ (handle->type & MP4_TYPE_AMR_WB) ||
+ ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio))))
+ {
+ *framespersample = 1;
+
+ return 0;
+ }
+
+
+ if (!handle->moov)
+ return -1;
+
+ if (!handle->moov->trakAudio)
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia)
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia->minf)
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl)
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd)
+ return -1;
+
+ if (handle->type & MP4_TYPE_AMR_NB)
+ {
+/* Now, framespersample returns the maximum frames_per_sample listed in the AMR sample entries*/
+ for (sampleentryindex = 0; (mp4_u8) sampleentryindex < handle->moov->trakAudio->mdia->minf->stbl->stsd->entryCount; sampleentryindex++)
+ {
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[sampleentryindex])
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[sampleentryindex]->damr)
+ return -1;
+
+ if (*framespersample < handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[sampleentryindex]->damr->framesPerSample)
+ *framespersample = handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[sampleentryindex]->damr->framesPerSample;
+ }
+ }
+ else if (handle->type & MP4_TYPE_AMR_WB)
+ {
+/* Now, framespersample returns the maximum frames_per_sample listed in the AMR sample entries*/
+ for (sampleentryindex = 0; (mp4_u8)sampleentryindex < handle->moov->trakAudio->mdia->minf->stbl->stsd->entryCount; sampleentryindex++)
+ {
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[sampleentryindex])
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[sampleentryindex]->damr)
+ return -1;
+
+ if (*framespersample < handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[sampleentryindex]->damr->framesPerSample)
+ *framespersample = handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[sampleentryindex]->damr->framesPerSample;
+ }
+ }
+ else if ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio))
+ {
+/* Now, framespersample returns the maximum frames_per_sample listed in the QCELP-13K sample entries*/
+ for (sampleentryindex = 0; (mp4_u8)sampleentryindex < handle->moov->trakAudio->mdia->minf->stbl->stsd->entryCount; sampleentryindex++)
+ {
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[sampleentryindex])
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[sampleentryindex]->dqcp)
+ return -1;
+
+ if (*framespersample < handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[sampleentryindex]->dqcp->framesPerSample)
+ *framespersample = handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[sampleentryindex]->dqcp->framesPerSample;
+ }
+ }
+ else
+ {
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 determineAudioTimeScale(MP4HandleImp handle,
+ * mp4_u32 *timescale)
+ *
+ * Description:
+ *
+ * This function determines the timescale of audio track.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * timescale Timescale of audio track is returned here
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 determineAudioTimeScale(MP4HandleImp handle, mp4_u32 *timescale)
+{
+ if (timescale == NULL)
+ return 0;
+
+ if (!handle)
+ return -1;
+ if (!handle->moov)
+ return -1;
+ if (!handle->moov->trakAudio)
+ return -1;
+ if (!handle->moov->trakAudio->mdia)
+ return -1;
+ if (!handle->moov->trakAudio->mdia->mdhd)
+ return -1;
+
+
+ if (handle->moov->trakAudio->mdia->mdhd->timeScale == 0)
+ return -1;
+
+ *timescale = handle->moov->trakAudio->mdia->mdhd->timeScale;
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 determineAudioAverageBitRate(MP4HandleImp handle,
+ * mp4_u32 *averagebitrate)
+ *
+ * Description:
+ *
+ * This function determines the average bitrate of the audio in bits per
+ * second.
+ *
+ * The average is calculated so that the audio data length is divided by
+ * the length of the audio track.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * averagebitrate Result is returned here
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 determineAudioAverageBitRate(MP4HandleImp handle, mp4_u32 *averagebitrate)
+ {
+ mp4_u32 audiosize = 0;
+
+ if (!handle->moov)
+ {
+ return -1;
+ }
+
+ if (handle->moov->trakAudio)
+ {
+ if (!handle->moov->trakAudio->mdia)
+ {
+ return -1;
+ }
+
+ if (!handle->moov->trakAudio->mdia->minf)
+ {
+ return -1;
+ }
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl)
+ {
+ return -1;
+ }
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsz)
+ {
+ return -1;
+ }
+
+ if (handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleSize != 0)
+ {
+ audiosize += (handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleCount *
+ handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleSize);
+ }
+ else
+ {
+ mp4_u32 i;
+ for (i = 0; i < handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleCount; i++)
+ {
+ audiosize += handle->moov->trakAudio->mdia->minf->stbl->stsz->entrySize[i];
+ }
+ }
+ }
+ else
+ {
+ return -1;
+ }
+
+ if (!handle->moov->trakAudio->mdia->mdhd)
+ {
+ return -1;
+ }
+
+ if (!handle->moov->trakAudio->mdia->mdhd->timeScale)
+ {
+ return -1;
+ }
+
+ if (handle->moov->trakAudio->mdia->mdhd->duration == 0)
+ {
+ *averagebitrate = 0;
+ }
+ else
+ {
+ *averagebitrate = (mp4_u32)((mp4_double)8 *
+ (mp4_double)audiosize /
+ ((mp4_double)handle->moov->trakAudio->mdia->mdhd->duration /
+ (mp4_double)handle->moov->trakAudio->mdia->mdhd->timeScale));
+ }
+
+ return 0;
+ }
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 determineStreamSize(MP4HandleImp handle,
+ * mp4_u32 *streamsize)
+ *
+ * Description:
+ *
+ * This function determines the size of media data in MP4 file/stream.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * streamsize Size of data
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 determineStreamSize(MP4HandleImp handle, mp4_u32 *streamsize)
+{
+ *streamsize = 0;
+
+ if (!handle->moov)
+ return -1;
+
+ if ((!handle->moov->trakAudio) && (!handle->moov->trakVideo))
+ return -1;
+
+ if (handle->moov->trakAudio)
+ {
+ if (!handle->moov->trakAudio->mdia)
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia->minf)
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl)
+ return -1;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsz)
+ return -1;
+
+ if (handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleSize != 0)
+ *streamsize += handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleCount *
+ handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleSize;
+ else
+ {
+ mp4_u32 i;
+
+ for (i = 0; i < handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleCount; i++)
+ *streamsize += handle->moov->trakAudio->mdia->minf->stbl->stsz->entrySize[i];
+ }
+ }
+
+ if (handle->moov->trakVideo)
+ {
+ if (!handle->moov->trakVideo->mdia)
+ return -1;
+
+ if (!handle->moov->trakVideo->mdia->minf)
+ return -1;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return -1;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsz)
+ return -1;
+
+ if (handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleSize != 0)
+ *streamsize += handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount *
+ handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleSize;
+ else
+ {
+ mp4_u32 i;
+
+ for (i = 0; i < handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount; i++)
+ *streamsize += handle->moov->trakVideo->mdia->minf->stbl->stsz->entrySize[i];
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 determineStreamAverageBitRate(MP4HandleImp handle,
+ * mp4_u32 *streamaveragebitrate,
+ * mp4_u32 streamsize)
+ *
+ * Description:
+ *
+ * This function determines the average bitrate of the stream in bits per
+ * second.
+ *
+ * The average is calculated so that the media data length is divided by
+ * the length of the presentation.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * streamaveragebitrate Result is returned here
+ * streamsize Size of media data in bytes
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 determineStreamAverageBitRate(MP4HandleImp handle, mp4_u32 *streamaveragebitrate, mp4_u32 streamsize)
+{
+ if (!handle->moov)
+ return -1;
+
+ if (!handle->moov->mvhd)
+ return -1;
+
+ if (!handle->moov->mvhd->timeScale)
+ return -1;
+
+ if (handle->moov->mvhd->atomhdr->version == 1) /* 64 bit */
+ {
+ if (!handle->moov->mvhd->duration64)
+ return -1;
+
+ *streamaveragebitrate = (mp4_u32)((mp4_double)8 * (mp4_double)streamsize /
+ ((mp4_double)handle->moov->mvhd->duration64 / handle->moov->mvhd->timeScale));
+ }
+ else /* 32 bit */
+ {
+ if (!handle->moov->mvhd->duration)
+ return -1;
+
+ *streamaveragebitrate = (mp4_u32)((mp4_double)8 * (mp4_double)streamsize /
+ ((mp4_double)handle->moov->mvhd->duration / handle->moov->mvhd->timeScale));
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 advanceVideoFrame(MP4HandleImp handle,
+ * trackAtom *trak)
+ *
+ * Description:
+ *
+ * This function Advances one video frame and finds the frame offset
+ * and size.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * trak TRAK atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 advanceVideoFrame(MP4HandleImp handle, trackAtom *trak)
+{
+ if (!trak->mdia)
+ return -1;
+ if (!trak->mdia->minf)
+ return -1;
+ if (!trak->mdia->minf->stbl)
+ return -1;
+ if (!trak->mdia->minf->stbl->stsz)
+ return -1;
+
+ /* Are there frames (samples) left? */
+
+ if (trak->mdia->minf->stbl->stsz->sampleCount > handle->videoSampleNum)
+ handle->videoSampleNum++;
+ else
+ return -2;
+
+ /* Find the size of the frame (sample) */
+
+ if (resolveVideoSampleSize(handle, trak->mdia->minf->stbl->stsz) < 0)
+ return -1;
+
+ /* Find the offset of the frame (sample) */
+
+ if (resolveVideoSampleOffset(handle, trak->mdia->minf->stbl) < 0)
+ return -1;
+
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 resolveVideoSampleOffset(MP4HandleImp handle,
+ * sampleTableAtom *stbl)
+ *
+ * Description:
+ *
+ * This function finds the offset of the current video sample.
+ * The result is stored in handle->videoFrameOffset.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stbl STBL atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 resolveVideoSampleOffset(MP4HandleImp handle, sampleTableAtom *stbl)
+ {
+ mp4_u32 chunk; /* Current chunk number */
+ mp4_u32 sample; /* Number of samples before this run of chunks */
+ mp4_u32 entry; /* Current entry in sample to chunk */
+ mp4_u32 chunksInThisRun; /* Number of chunks in this run */
+ mp4_u32 sampleNrInChunk = 0; /* Sample number in the chunk */
+
+ if (!stbl->stsc || stbl->stsc->entryCount == 0)
+ {
+ return -1;
+ }
+
+ if (!stbl->stco || stbl->stco->entryCount == 0)
+ {
+ return -1;
+ }
+
+ chunk = 0;
+ sample = 0;
+ entry = 0;
+
+ for (;;)
+ {
+ /* Find how many chunks there are in this run */
+
+ if (stbl->stsc->entryCount > entry + 1) /* Not last chunk run */
+ {
+ chunksInThisRun = stbl->stsc->firstChunk[entry + 1] - stbl->stsc->firstChunk[entry];
+ }
+ else
+ {
+ chunksInThisRun = stbl->stco->entryCount - chunk + 1;
+ }
+
+ if (handle->videoSampleNum <= chunksInThisRun * stbl->stsc->samplesPerChunk[entry] + sample)
+ {
+ chunk += (handle->videoSampleNum - sample + stbl->stsc->samplesPerChunk[entry] - 1) / stbl->stsc->samplesPerChunk[entry];
+ sampleNrInChunk = (handle->videoSampleNum - sample + stbl->stsc->samplesPerChunk[entry] - 1) % stbl->stsc->samplesPerChunk[entry];
+
+ /* The following functions are needed for multiple sample entry support */
+ handle->videoSampleEntryIndex = stbl->stsc->sampleDescriptionIndex[entry];
+
+ break; /* We know the chunk number and sample number in chunk AND the sample entry index of the current sample*/
+ }
+ else
+ {
+ chunk += chunksInThisRun;
+ sample += chunksInThisRun * stbl->stsc->samplesPerChunk[entry];
+ }
+
+ entry++;
+ }
+
+ if (chunk > stbl->stco->entryCount)
+ {
+ return -1;
+ }
+
+ handle->videoFrameOffset = getChunkOffset(stbl, chunk - 1);
+
+ if (sampleNrInChunk)
+ {
+ if (stbl->stsz->sampleSize)
+ {
+ handle->videoFrameOffset += stbl->stsz->sampleSize * sampleNrInChunk;
+ }
+ else
+ {
+ if (stbl->stsz->sampleCount == 0)
+ {
+ return -1;
+ }
+ while (sampleNrInChunk)
+ {
+ handle->videoFrameOffset += stbl->stsz->entrySize[handle->videoSampleNum - sampleNrInChunk - 1];
+ sampleNrInChunk--;
+ }
+ }
+ }
+
+
+ //PRINT((_L("videoFrameOffset %Lu"), handle->videoFrameOffset));
+ return 0;
+ }
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 resolveVideoSampleSize(MP4HandleImp handle,
+ * sampleSizeAtom *stsz)
+ *
+ * Description:
+ *
+ * This function finds the size of the current video sample.
+ * The result is stored in handle->videoFrameSize.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stsz STSZ atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 resolveVideoSampleSize(MP4HandleImp handle, sampleSizeAtom *stsz)
+ {
+ if (stsz->sampleSize)
+ {
+ handle->videoFrameSize = stsz->sampleSize;
+ return 0;
+ }
+
+ if (stsz->sampleCount == 0)
+ {
+ return -1;
+ }
+ handle->videoFrameSize = stsz->entrySize[handle->videoSampleNum - 1];
+
+ return 0;
+ }
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 fetchVideoFrame(MP4HandleImp handle,
+ * trackAtom *trak,
+ * mp4_u8 *buffer,
+ * mp4_u32 buffersize,
+ * mp4_u32 *framesize,
+ * mp4_u32 *timestamp,
+ * mp4_bool *keyframe,
+ * mp4_u32 *timestamp2)
+ *
+ * Description:
+ *
+ * This function fetches one video frame from a file.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * trak TRAK atom pointer
+ * buffer Video frame is retuned here
+ * buffersize Size of buffer
+ * framesize Size of returned frame in bytes
+ * timestamp Frame time in milliseconds (from the beginning of the
+ * presentation)
+ * keyframe True if intra frame, false otherwise
+ * timestamp2 Frame time in timescale (from the beginning of the
+ * presentation)
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 fetchVideoFrame(MP4HandleImp handle,
+ trackAtom *trak,
+ mp4_u8 *buffer,
+ mp4_u32 buffersize,
+ mp4_u32 *framesize,
+ mp4_u32 *timestamp,
+ mp4_bool *keyframe,
+ mp4_u32 *timestamp2)
+{
+ mp4_i32 bytesread;
+
+
+ if (!trak->mdia)
+ return -1;
+
+ if (handle->file) /* Input is in a file */
+ {
+ if (seekFileAbs(handle, handle->videoFrameOffset) != 0)
+ return -4;
+ }
+ else /* Input is a stream */
+ {
+ if (handle->videoFrameOffset + handle->videoFrameSize <= getCumulativeBufferedBytes(handle))
+ {
+ handle->absPosition = handle->videoFrameOffset;
+ }
+ else
+ return -3;
+ }
+
+ if (handle->videoFrameSize > buffersize)
+ {
+ *framesize = handle->videoFrameSize;
+ return -2;
+ }
+
+ bytesread = readData(handle, buffer, handle->videoFrameSize);
+ switch (bytesread)
+ {
+ case -1:
+ return -1;
+ case -2:
+ return -4;
+ case -10:
+ return -3;
+ default:
+ break;
+ }
+
+ if (handle->file)
+ if (handle->videoFrameOffset + handle->videoFrameSize - 1 > handle->lastAccessedPosInFile)
+ handle->lastAccessedPosInFile = handle->videoFrameOffset + handle->videoFrameSize - 1;
+
+ *framesize = handle->videoFrameSize;
+
+ if (convertVideoSampleToTime(handle, trak->mdia, timestamp, timestamp2) < 0)
+ return -1;
+
+ if (isVideoFrameKeyFrame(handle, trak, keyframe) < 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 fetchVideoFrameAsync(MP4HandleImp handle,
+ * trackAtom *trak,
+ * mp4_u8 *buffer,
+ * mp4_u32 buffersize,
+ *
+ * Description:
+ *
+ * This function fetches one video frame from a file asyncronously.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * trak TRAK atom pointer
+ * buffer Video frame is retuned here
+ * buffersize Size of buffer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 fetchVideoFrameAsync(MP4HandleImp handle,
+ trackAtom *trak,
+ mp4_u8 *buffer,
+ mp4_u32 *buffersize)
+{
+ if (trak)
+ {
+ if (!trak->mdia)
+ return -1;
+ }
+ else
+ {
+ return -1;
+ }
+
+ if (handle->videoFrameSize > *buffersize)
+ {
+ *buffersize = handle->videoFrameSize;
+ return -2;
+ }
+
+ if ( handle->asyncReader == NULL )
+ {
+ TRAPD(error, handle->asyncReader = CFileAsyncParser::NewL( handle, (RFile64&)handle->rfile ));
+ if ( error != KErrNone )
+ {
+ if (error == KErrNoMemory )
+ {
+ return MP4_OUT_OF_MEMORY;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ }
+
+ return handle->asyncReader->ReadVideoFrame( buffer, handle->videoFrameOffset, handle->videoFrameSize);
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 isVideoFrameKeyFrame(MP4HandleImp handle,
+ * trackAtom *trak,
+ * mp4_bool *keyframe)
+ *
+ * Description:
+ *
+ * This function determines if the current frame is a keyframe (intra)
+ * or not.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * trak TRAK atom pointer
+ * keyframe Has a value of MP4TRUE if current frame is a keyframe
+ * (intra) or MP4FALSE otherwise
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 isVideoFrameKeyFrame(MP4HandleImp handle, trackAtom *trak, mp4_bool *keyframe)
+{
+ mp4_u32 i;
+
+
+ *keyframe = MP4FALSE;
+
+ if (!trak->mdia)
+ return -1;
+
+ if (!trak->mdia->minf)
+ return -1;
+
+ if (!trak->mdia->minf->stbl)
+ return -1;
+
+ if (!trak->mdia->minf->stbl->stss)
+ {
+ *keyframe = MP4TRUE;
+
+ return 0;
+ }
+
+ for (i = 0; i < trak->mdia->minf->stbl->stss->entryCount; i++)
+ {
+ if (trak->mdia->minf->stbl->stss->sampleNumber[i] == handle->videoSampleNum)
+ {
+ *keyframe = MP4TRUE;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 convertVideoSampleToTime(MP4HandleImp handle,
+ * mediaAtom *mdia,
+ * mp4_u32 *timestamp,
+ * mp4_u32 *timestamp2)
+ *
+ * Description:
+ *
+ * This function converts a video sample to corresponding time.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * mdia MDIA atom pointer
+ * timestamp Time in milliseconds is returned here
+ * timestamp2 Time in timescale is returned here
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 convertVideoSampleToTime(MP4HandleImp handle,
+ mediaAtom *mdia,
+ mp4_u32 *timestamp,
+ mp4_u32 *timestamp2)
+ {
+ mp4_u32 tmptime;
+ mp4_double tmptime2;
+ mp4_u32 sample;
+ mp4_u32 entry;
+
+ if (!mdia->mdhd)
+ {
+ return -1;
+ }
+ if (!mdia->minf)
+ {
+ return -1;
+ }
+ if (!mdia->minf->stbl)
+ {
+ return -1;
+ }
+ if (!mdia->minf->stbl->stts)
+ {
+ return -1;
+ }
+ if (mdia->minf->stbl->stts->entryCount == 0)
+ {
+ return -1;
+ }
+
+ tmptime = 0;
+ sample = 0;
+ entry = 0;
+
+ for (;;)
+ {
+ if (sample + mdia->minf->stbl->stts->sampleCount[entry] < handle->videoSampleNum)
+ {
+ sample += mdia->minf->stbl->stts->sampleCount[entry];
+ tmptime += (mdia->minf->stbl->stts->sampleCount[entry] * mdia->minf->stbl->stts->sampleDelta[entry]);
+ entry++;
+ if (entry == mdia->minf->stbl->stts->entryCount)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ tmptime += ((handle->videoSampleNum - sample - 1) * mdia->minf->stbl->stts->sampleDelta[entry]);
+ break;
+ }
+ }
+
+ if (mdia->mdhd->timeScale == 0)
+ {
+ return -1;
+ }
+
+ if (timestamp2)
+ {
+ *timestamp2 = tmptime;
+ }
+
+ tmptime2 = (mp4_double)tmptime * (mp4_double)1000 / (mp4_double)mdia->mdhd->timeScale + (mp4_double)0.5;
+
+ *timestamp = (mp4_u32)tmptime2;
+
+ return 0;
+ }
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 advanceAudioSample(MP4HandleImp handle,
+ * trackAtom *trak)
+ *
+ * Description:
+ *
+ * This function advances one audio sample and finds the sample
+ * offset and sample size.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * trak TRAK atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 advanceAudioSample(MP4HandleImp handle,
+ trackAtom *trak)
+{
+ if (!trak->mdia)
+ return -1;
+ if (!trak->mdia->minf)
+ return -1;
+ if (!trak->mdia->minf->stbl)
+ return -1;
+ if (!trak->mdia->minf->stbl->stsz)
+ return -1;
+
+
+ /* Are there samples left? */
+
+ if (trak->mdia->minf->stbl->stsz->sampleCount > handle->audioSampleNum)
+ handle->audioSampleNum++;
+ else
+ return -2;
+
+ /* Find the size of the sample */
+
+ if (resolveAudioSampleSize(handle, trak->mdia->minf->stbl->stsz) < 0)
+ return -1;
+
+ /* Find the offset of the sample */
+
+ if (resolveAudioSampleOffset(handle, trak->mdia->minf->stbl) < 0)
+ return -1;
+
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 resolveAudioSampleOffset(MP4HandleImp handle,
+ * sampleTableAtom *stbl)
+ *
+ * Description:
+ *
+ * This function finds the offset of the current audio sample.
+ * The result is stored in handle->audioSampleOffset.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stbl STBL atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 resolveAudioSampleOffset(MP4HandleImp handle, sampleTableAtom *stbl)
+{
+ mp4_u32 chunk; /* Current chunk number */
+ mp4_u32 sample; /* Number of samples before this run of chunks */
+ mp4_u32 entry; /* Current entry in sample to chunk */
+ mp4_u32 chunksInThisRun; /* Number of chunks in this run */
+ mp4_u32 sampleNrInChunk; /* Sample number in the chunk */
+
+
+ if (!stbl->stsc || stbl->stsc->entryCount == 0)
+ return -1;
+ if (!stbl->stco || stbl->stco->entryCount == 0)
+ return -1;
+
+ chunk = 0;
+ sample = 0;
+ entry = 0;
+
+ for (;;)
+ {
+ /* Find how many chunks there are in this run */
+
+ if (stbl->stsc->entryCount > entry + 1) /* Not last chunk run */
+ {
+ chunksInThisRun = stbl->stsc->firstChunk[entry + 1] -
+ stbl->stsc->firstChunk[entry];
+ }
+ else
+ chunksInThisRun = stbl->stco->entryCount - chunk + 1;
+
+
+ if (handle->audioSampleNum <= chunksInThisRun * stbl->stsc->samplesPerChunk[entry] + sample)
+ {
+ chunk += (handle->audioSampleNum - sample + stbl->stsc->samplesPerChunk[entry] - 1) / stbl->stsc->samplesPerChunk[entry];
+ sampleNrInChunk = (handle->audioSampleNum - sample + stbl->stsc->samplesPerChunk[entry] - 1) % stbl->stsc->samplesPerChunk[entry];
+
+ /* The following functions are needed for multiple sample entry support */
+ handle->audioSampleEntryIndex = stbl->stsc->sampleDescriptionIndex[entry];
+
+ break; /* We know the chunk number and sample number in chunk AND the sample entry index of the current sample*/
+ }
+ else
+ {
+ chunk += chunksInThisRun;
+ sample += chunksInThisRun * stbl->stsc->samplesPerChunk[entry];
+ }
+
+ entry++;
+ }
+
+ if (chunk > stbl->stco->entryCount)
+ return -1;
+
+ handle->audioSampleOffset = getChunkOffset(stbl, chunk - 1);
+
+ if (sampleNrInChunk)
+ {
+ if (stbl->stsz->sampleSize)
+ {
+ handle->audioSampleOffset += stbl->stsz->sampleSize * sampleNrInChunk;
+ }
+ else
+ {
+ if (stbl->stsz->sampleCount == 0)
+ {
+ // ensure there are entries in the entrySize array
+ return -1;
+ }
+
+ while (sampleNrInChunk)
+ {
+ handle->audioSampleOffset += stbl->stsz->entrySize[handle->audioSampleNum - sampleNrInChunk - 1];
+ sampleNrInChunk--;
+ }
+ }
+ }
+
+ //PRINT((_L("audioSampleOffset %Lu"), handle->audioSampleOffset));
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 resolveAudioSampleSize(MP4HandleImp handle,
+ * sampleSizeAtom *stsz)
+ *
+ * Description:
+ *
+ * This function finds the size of the current audio sample.
+ * The result is stored in handle->audioSampleSize.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * stsz STSZ atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 resolveAudioSampleSize(MP4HandleImp handle, sampleSizeAtom *stsz)
+ {
+ if (stsz->sampleSize)
+ {
+ handle->audioSampleSize = stsz->sampleSize;
+ return 0;
+ }
+
+ if (stsz->sampleCount == 0)
+ {
+ return -1;
+ }
+ handle->audioSampleSize = stsz->entrySize[handle->audioSampleNum - 1];
+
+ return 0;
+ }
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 fetchAudioSample(MP4HandleImp handle,
+ * trackAtom *trak,
+ * mp4_u8 *buffer,
+ * mp4_u32 buffersize,
+ * mp4_u32 *framesize,
+ * mp4_u32 *timestamp,
+ * mp4_u32 *returnedframes,
+ * mp4_u32 *timestamp2)
+ *
+ * Description:
+ *
+ * This function fetches one audio sample from a file.
+ *
+ * Note: returnedframes may differ from the correct value when accessing
+ * the last audio sample.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * trak TRAK atom pointer
+ * buffer Audio frame is retuned here
+ * buffersize Size of buffer
+ * framesize Size of returned frame in bytes
+ * timestamp Frame time in milliseconds (from the beginning of the
+ * presentation)
+ * returnedframes Number of frames returned, of 0 if not known
+ * timestamp2 Frame time in timescale (from the beginning of the
+ * presentation)
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 fetchAudioSample(MP4HandleImp handle,
+ trackAtom *trak,
+ mp4_u8 *buffer,
+ mp4_u32 buffersize,
+ mp4_u32 *framesize,
+ mp4_u32 *timestamp,
+ mp4_u32 *returnedframes,
+ mp4_u32 *timestamp2)
+{
+ mp4_i32 bytesread;
+ mp4_i32 frameLength;
+ mp4_u32 numOfFrames;
+ mp4_u8 *framepointer;
+ mp4_u32 rawAmrFrameLength[16] = {13,14,16,18,20,21,27,32,6,0,0,0,0,0,0,1};
+
+ if (!trak->mdia)
+ return -1;
+
+ if (handle->file) /* Input is in a file */
+ {
+ if (seekFileAbs(handle, handle->audioSampleOffset) != 0)
+ return -4;
+ }
+ else /* Input is a stream */
+ {
+ if (handle->audioSampleOffset + handle->audioSampleSize <= getCumulativeBufferedBytes(handle))
+ {
+ handle->absPosition = handle->audioSampleOffset;
+ }
+ else
+ return -3;
+ }
+
+ if (handle->audioSampleSize > buffersize)
+ {
+ *framesize = handle->audioSampleSize;
+ return -2;
+ }
+
+ bytesread = readData(handle, buffer, handle->audioSampleSize);
+ switch (bytesread)
+ {
+ case -1:
+ return -1;
+ case -2:
+ return -4;
+ case -10:
+ return -3;
+ default:
+ break;
+ }
+
+ if (handle->file)
+ if (handle->audioSampleOffset + handle->audioSampleSize - 1 > handle->lastAccessedPosInFile)
+ handle->lastAccessedPosInFile = handle->audioSampleOffset + handle->audioSampleSize - 1;
+
+ *framesize = handle->audioSampleSize;
+ if (convertAudioSampleToTime(handle, trak->mdia, timestamp, timestamp2) < 0)
+ return -1;
+
+ *returnedframes = 0;
+
+ /* AMR */
+ if (trak->mdia->minf)
+ if (trak->mdia->minf->stbl)
+ if (trak->mdia->minf->stbl->stsd)
+ if (handle->type & MP4_TYPE_AMR_NB)
+ {
+ framepointer = buffer;
+ numOfFrames = 0;
+ while ( bytesread > 0 )
+ {
+ frameLength = rawAmrFrameLength[(TInt)(((*framepointer) & 0x78) >> 3)];
+ if ( frameLength == 0)
+ {
+ return -4;
+ }
+ bytesread -= frameLength;
+ framepointer += frameLength;
+ numOfFrames++;
+ }
+ *returnedframes = numOfFrames;
+
+ /* Return the number of sample entries listed for this particular sample entry index
+ if (trak->mdia->minf->stbl->stsd->samr[handle->audioSampleEntryIndex - 1])
+ if (trak->mdia->minf->stbl->stsd->samr[handle->audioSampleEntryIndex - 1]->damr)
+ *returnedframes = trak->mdia->minf->stbl->stsd->samr[handle->audioSampleEntryIndex - 1]->damr->framesPerSample;*/
+ }
+ else if (handle->type & MP4_TYPE_AMR_WB)
+ {
+ /* Return the number of sample entries listed for this particular sample entry index */
+ if (trak->mdia->minf->stbl->stsd->sawb[handle->audioSampleEntryIndex - 1])
+ if (trak->mdia->minf->stbl->stsd->sawb[handle->audioSampleEntryIndex - 1]->damr)
+ *returnedframes = trak->mdia->minf->stbl->stsd->sawb[handle->audioSampleEntryIndex - 1]->damr->framesPerSample;
+ }
+ else
+ {
+ }
+
+ /* MPEG-4 audio */
+ if (trak->mdia->minf)
+ if (trak->mdia->minf->stbl)
+ if (trak->mdia->minf->stbl->stsd)
+ if (trak->mdia->minf->stbl->stsd->mp4a[handle->audioSampleEntryIndex - 1])
+ *returnedframes = 1;
+
+ /* QCELP 13K as QCELPSampleEntry*/
+ if (trak->mdia->minf)
+ if (trak->mdia->minf->stbl)
+ if (trak->mdia->minf->stbl->stsd)
+ if ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio))
+ {
+ /* Return the number of sample entries listed for this particular sample entry index */
+ if (trak->mdia->minf->stbl->stsd->sqcp[handle->audioSampleEntryIndex - 1])
+ if (trak->mdia->minf->stbl->stsd->sqcp[handle->audioSampleEntryIndex - 1]->dqcp)
+ *returnedframes = trak->mdia->minf->stbl->stsd->sqcp[handle->audioSampleEntryIndex - 1]->dqcp->framesPerSample;
+ }
+
+ /* QCELP 13K as MPEG-4 audio */
+ if (trak->mdia->minf)
+ if (trak->mdia->minf->stbl)
+ if (trak->mdia->minf->stbl->stsd)
+ if (trak->mdia->minf->stbl->stsd->mp4a[handle->audioSampleEntryIndex - 1])
+ *returnedframes = 1;
+
+ return 0;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 fetchAudioSampleAsync(MP4HandleImp handle,
+ * trackAtom *trak,
+ * mp4_u8 *buffer,
+ * mp4_u32 buffersize,
+ *
+ * Description:
+ *
+ * This function fetches one audio sample from a file asyncronously.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * trak TRAK atom pointer
+ * buffer Audio frame is retuned here
+ * buffersize Size of buffer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 fetchAudioSampleAsync(MP4HandleImp handle,
+ trackAtom *trak,
+ mp4_u8 *buffer,
+ mp4_u32 *buffersize)
+{
+ if (trak)
+ {
+ if (!trak->mdia)
+ return -1;
+ }
+ else
+ {
+ return -1;
+ }
+
+ if (handle->audioSampleSize > *buffersize)
+ {
+ *buffersize = handle->audioSampleSize;
+ return -2;
+ }
+
+ if (!handle->file) // Other input than file is not supported
+ {
+ return -1;
+ }
+
+ if ( handle->asyncReader == NULL )
+ {
+ TRAPD(error, handle->asyncReader = CFileAsyncParser::NewL( handle, (RFile64&)handle->rfile ));
+ if ( error != KErrNone )
+ {
+ if (error == KErrNoMemory )
+ {
+ return MP4_OUT_OF_MEMORY;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ }
+
+ return handle->asyncReader->ReadAudioFrames( buffer, handle->audioSampleOffset, handle->audioSampleSize);
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 convertAudioSampleToTime(MP4HandleImp handle,
+ * mediaAtom *mdia,
+ * mp4_u32 *timestamp,
+ * mp4_u32 *timestamp2)
+ *
+ * Description:
+ *
+ * This function converts an audio sample to corresponding time.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * mdia MDIA atom pointer
+ * timestamp Time in milliseconds is returned here
+ * timestamp2 Time in timescale is returned here
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 convertAudioSampleToTime(MP4HandleImp handle,
+ mediaAtom *mdia,
+ mp4_u32 *timestamp,
+ mp4_u32 *timestamp2)
+ {
+ mp4_u32 tmptime;
+ mp4_double tmptime2;
+ mp4_u32 sample;
+ mp4_u32 entry;
+
+ if (!mdia->mdhd)
+ {
+ return -1;
+ }
+ if (!mdia->minf)
+ {
+ return -1;
+ }
+ if (!mdia->minf->stbl)
+ {
+ return -1;
+ }
+ if (!mdia->minf->stbl->stts)
+ {
+ return -1;
+ }
+ if (mdia->minf->stbl->stts->entryCount == 0)
+ {
+ return -1;
+ }
+
+ tmptime = 0;
+ sample = 0;
+ entry = 0;
+
+ for (;;)
+ {
+ if (sample + mdia->minf->stbl->stts->sampleCount[entry] < handle->audioSampleNum)
+ {
+ sample += mdia->minf->stbl->stts->sampleCount[entry];
+ tmptime += mdia->minf->stbl->stts->sampleCount[entry] *
+ mdia->minf->stbl->stts->sampleDelta[entry];
+ entry++;
+
+ if (entry == mdia->minf->stbl->stts->entryCount)
+ return -1;
+ }
+ else
+ {
+ tmptime += (handle->audioSampleNum - sample - 1) * mdia->minf->stbl->stts->sampleDelta[entry];
+ break;
+ }
+ }
+
+ if (mdia->mdhd->timeScale == 0)
+ {
+ return -1;
+ }
+
+ if (timestamp2)
+ {
+ *timestamp2 = tmptime;
+ }
+
+ tmptime2 = (mp4_double)tmptime * (mp4_double)1000 / (mp4_double)mdia->mdhd->timeScale + (mp4_double)0.5;
+
+ *timestamp = (mp4_u32)tmptime2;
+
+ return 0;
+ }
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 convertTimeToSample(MP4HandleImp handle,
+ * trackAtom *trak,
+ * mp4_u32 position,
+ * mp4_u32 *sample)
+ *
+ * Description:
+ *
+ * This function converts time to corresponding sample number.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * trak trackAtom pointer
+ * position Time in milliseconds
+ * sample Sample number is returned here
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 convertTimeToSample(MP4HandleImp handle,
+ trackAtom *trak,
+ mp4_u32 position,
+ mp4_u32 *sample)
+{
+ mp4_u32 pos; /* Target position in media timescale */
+ mp4_u32 tmppos; /* Temporary position counter */
+ mp4_u32 i;
+
+
+ if (!handle)
+ return -1;
+ if (!trak)
+ return -1;
+ if (!trak->mdia)
+ return -1;
+ if (!trak->mdia->mdhd)
+ return -1;
+ if (!trak->mdia->minf)
+ return -1;
+ if (!trak->mdia->minf->stbl)
+ return -1;
+ if (!trak->mdia->minf->stbl->stts)
+ return -1;
+ if (trak->mdia->minf->stbl->stts->entryCount == 0)
+ return -1;
+
+ *sample = 1;
+ tmppos = 0;
+
+ pos = (mp4_u32)((mp4_double)position / (mp4_double)1000 * (mp4_double)trak->mdia->mdhd->timeScale + (mp4_double)0.5);
+
+ for (i = 0; i < trak->mdia->minf->stbl->stts->entryCount; i++)
+ {
+ if (pos >= (tmppos + trak->mdia->minf->stbl->stts->sampleCount[i] *
+ trak->mdia->minf->stbl->stts->sampleDelta[i]))
+ {
+ *sample += trak->mdia->minf->stbl->stts->sampleCount[i];
+ tmppos += (trak->mdia->minf->stbl->stts->sampleCount[i] *
+ trak->mdia->minf->stbl->stts->sampleDelta[i]);
+
+ if (i == trak->mdia->minf->stbl->stts->entryCount - 1) /* Last entry */
+ *sample = *sample - 1;
+ }
+ else
+ {
+ if (trak->mdia->minf->stbl->stts->sampleDelta[i] == 0)
+ return -1;
+
+ *sample += ((pos - tmppos) / trak->mdia->minf->stbl->stts->sampleDelta[i]);
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 goToVideoSample(MP4HandleImp handle,
+ * trackAtom *trak,
+ * mp4_u32 sample)
+ *
+ * Description:
+ *
+ * This function moves to video sample indicated by sample and finds the
+ * sample offset and sample size.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * trak TRAK atom pointer
+ * sample Sample to go to
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 goToVideoSample(MP4HandleImp handle,
+ trackAtom *trak,
+ mp4_u32 sample)
+{
+ if (!trak->mdia)
+ return -1;
+ if (!trak->mdia->minf)
+ return -1;
+ if (!trak->mdia->minf->stbl)
+ return -1;
+ if (!trak->mdia->minf->stbl->stsz)
+ return -1;
+
+
+ /* Is the sample valid? */
+
+ if (sample <= trak->mdia->minf->stbl->stsz->sampleCount)
+ handle->videoSampleNum = sample;
+ else
+ return -1;
+
+ /* Find the size of the sample */
+
+ if (resolveVideoSampleSize(handle, trak->mdia->minf->stbl->stsz) < 0)
+ return -1;
+
+ /* Find the offset of the sample */
+
+ if (resolveVideoSampleOffset(handle, trak->mdia->minf->stbl) < 0)
+ return -1;
+
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 goToAudioSample(MP4HandleImp handle,
+ * trackAtom *trak,
+ * mp4_u32 sample)
+ *
+ * Description:
+ *
+ * This function moves to audio sample indicated by sample and finds the
+ * sample offset and sample size.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * trak TRAK atom pointer
+ * sample Sample to go to
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 goToAudioSample(MP4HandleImp handle,
+ trackAtom *trak,
+ mp4_u32 sample)
+{
+ if (!trak->mdia)
+ return -1;
+ if (!trak->mdia->minf)
+ return -1;
+ if (!trak->mdia->minf->stbl)
+ return -1;
+ if (!trak->mdia->minf->stbl->stsz)
+ return -1;
+
+
+ /* Is the sample valid? */
+
+ if (sample <= trak->mdia->minf->stbl->stsz->sampleCount)
+ handle->audioSampleNum = sample;
+ else
+ return -1;
+
+ /* Find the size of the sample */
+
+ if (resolveAudioSampleSize(handle, trak->mdia->minf->stbl->stsz) < 0)
+ return -1;
+
+ /* Find the offset of the sample */
+
+ if (resolveAudioSampleOffset(handle, trak->mdia->minf->stbl) < 0)
+ return -1;
+
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 findVideoKeyFrame(MP4HandleImp handle,
+ * trackAtom *trak,
+ * mp4_u32 sample,
+ * mp4_u32 *newsample)
+ *
+ * Description:
+ *
+ * This function finds the video keyframe that is identical to or precedes
+ * the sample indicated by sample.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * trak TRAK atom pointer
+ * sample Sample number
+ * newsample Sample number of found keyframe
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 findVideoKeyFrame(MP4HandleImp handle,
+ trackAtom *trak,
+ mp4_u32 sample,
+ mp4_u32 *newsample)
+{
+ mp4_i32 i;
+
+
+ if (!handle)
+ return -1;
+ if (!trak->mdia)
+ return -1;
+ if (!trak->mdia->minf)
+ return -1;
+ if (!trak->mdia->minf->stbl)
+ return -1;
+
+ if (!trak->mdia->minf->stbl->stss) /* No sync sample atom => all samples are
+ random access points */
+ {
+ *newsample = sample;
+
+ return 0;
+ }
+ *newsample = 0;
+
+ for (i = trak->mdia->minf->stbl->stss->entryCount - 1; i >= 0; i--)
+ {
+ if (sample >= trak->mdia->minf->stbl->stss->sampleNumber[i])
+ {
+ *newsample = trak->mdia->minf->stbl->stss->sampleNumber[i];
+ break;
+ }
+ }
+
+ if (*newsample == 0)
+ return -1;
+
+ return 0;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readAVCC(MP4HandleImp handle,
+ * avcConfigurationAtom *avcc)
+ *
+ * Description:
+ *
+ * This function parses one avcc atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * avcc avcC pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readAVCC(MP4HandleImp handle, avcConfigurationAtom *avcc)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+ avcc->avcConfigSize = 0;
+
+ if ((avcc->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, avcc->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread +=bytesread;
+
+ if (avcc->atomhdr->type != ATOMTYPE_AVCC)
+ return -1;
+
+ /* read the avcDecoderConfigurationRecord */
+ if (avcc->atomhdr->size != 1)
+ avcc->avcConfigSize = avcc->atomhdr->size - 8;
+ else
+ avcc->avcConfigSize = (mp4_u32)(I64INT(avcc->atomhdr->largeSize) - 16);
+
+ avcc->avcConfig = (mp4_u8 *)mp4malloc(avcc->avcConfigSize);
+ if (avcc->avcConfig == 0)
+ return -100;
+
+ bytesread = readData(handle, avcc->avcConfig, avcc->avcConfigSize );
+
+ if (bytesread < 0)
+ return -1;
+ totalbytesread +=bytesread;
+ return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ * mp4_i32 readBTRT(MP4HandleImp handle,
+ * mpeg4BitrateAtom *btrt)
+ *
+ * Description:
+ *
+ * This function parses one btrt atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * btrt btrt pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readBTRT(MP4HandleImp handle, mpeg4BitrateAtom *btrt)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((btrt->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, btrt->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread +=bytesread;
+
+ if (btrt->atomhdr->type != ATOMTYPE_BTRT)
+ return -1;
+
+ /* read the mpeg4BitrateAtom */
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ btrt->bufferSizeDB = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread +=bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ btrt->maxBitRate = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread +=bytesread;
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ btrt->avgBitrate = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread +=bytesread;
+
+ return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 readM4DS(MP4HandleImp handle,
+ * mpeg4ExtensionDescriptorsAtom *m4ds)
+ *
+ * Description:
+ *
+ * This function parses one m4ds atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * m4ds m4ds pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readM4DS(MP4HandleImp handle, mpeg4ExtensionDescriptorsAtom *m4ds)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+ mp4_u32 i;
+
+ m4ds->descrSize = 0;
+
+ if ((m4ds->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, m4ds->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread +=bytesread;
+
+ if (m4ds->atomhdr->type != ATOMTYPE_M4DS)
+ return -1;
+
+ /* read the avcDecoderConfigurationRecord */
+ if (m4ds->atomhdr->size != 1)
+ bytesread = readData(handle, handle->buf, m4ds->atomhdr->size - 8);
+ else
+ bytesread = readData(handle, handle->buf, (mp4_u32)(I64INT(m4ds->atomhdr->largeSize) - 16) );
+
+ if (bytesread < 0)
+ return -1;
+ m4ds->descrSize = bytesread;
+ m4ds->descr = (mp4_u8 *)mp4malloc(m4ds->descrSize * sizeof(mp4_u8));
+
+ /* copy the mpeg4ExtensionDescriptors from the temp. buffer */
+ for(i = 0; i < m4ds->descrSize; i++)
+ m4ds->descr[i] = handle->buf[i];
+
+ totalbytesread +=bytesread;
+
+ return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 readAVC1(MP4HandleImp handle,
+ * avcSampleEntry *avc1)
+ *
+ * Description:
+ *
+ * This function parses one avc1 atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * avc1 avc1 pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readAVC1(MP4HandleImp handle, avcSampleEntry *avc1)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+ if ((avc1->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, avc1->atomhdr);
+
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (avc1->atomhdr->type != ATOMTYPE_AVC1)
+ return -1;
+
+ bytesread = discardData(handle, 6);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ avc1->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 16);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ avc1->width = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ avc1->height = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 50);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ /* Check for the present atoms */
+ while ((mp4_u32)totalbytesread < avc1->atomhdr->size)
+ {
+ mp4_u32 type;
+
+ if (peekData(handle, handle->buf, 8) < 0)
+ return -1;
+
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ switch (type)
+ {
+ case ATOMTYPE_AVCC:
+
+ if (avc1->avcc) /* avcC has already been read, more than one is not allowed. */
+ return -1;
+
+ if ((avc1->avcc = (avcConfigurationAtom *)mp4malloc(sizeof(avcConfigurationAtom))) == NULL)
+ return -100;
+
+ bytesread = readAVCC(handle, avc1->avcc);
+ if(bytesread < 0)
+ return -1;
+ totalbytesread +=bytesread;
+ break;
+
+ case ATOMTYPE_BTRT:
+
+ if (avc1->btrt) /* btrt has already been read, more than one is not allowed. */
+ return -1;
+
+ if ((avc1->btrt = (mpeg4BitrateAtom *)mp4malloc(sizeof(mpeg4BitrateAtom))) == NULL)
+ return -100;
+
+ bytesread = readBTRT(handle, avc1->btrt);
+ if(bytesread < 0)
+ return -1;
+ totalbytesread +=bytesread;
+ break;
+
+ case ATOMTYPE_M4DS:
+
+ if (avc1->m4ds) /* m4ds has already been read, more than one is not allowed. */
+ return -1;
+
+ if ((avc1->m4ds = (mpeg4ExtensionDescriptorsAtom *)mp4malloc(sizeof(mpeg4ExtensionDescriptorsAtom))) == NULL)
+ return -100;
+
+ bytesread = readM4DS(handle, avc1->m4ds);
+ if(bytesread < 0)
+ return -1;
+ totalbytesread +=bytesread;
+ break;
+
+ default:
+
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ break;
+
+ }
+ }
+
+ return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeAVCC(avcConfigurationAtom *avcc)
+ *
+ * Description:
+ *
+ * This function frees memory for avcc atom.
+ *
+ * Parameters:
+ *
+ * avcc avcc atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeAVCC(avcConfigurationAtom *avcc)
+{
+ if (avcc)
+ {
+ if (freeAtomHeader(avcc->atomhdr) < 0)
+ return -1;
+ if(avcc->avcConfig)
+ mp4free(avcc->avcConfig);
+
+ mp4free(avcc);
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeBTRT(mpeg4BitrateAtom *btrt)
+ *
+ * Description:
+ *
+ * This function frees memory for btrt atom.
+ *
+ * Parameters:
+ *
+ * btrt btrt atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeBTRT(mpeg4BitrateAtom *btrt)
+{
+ if (btrt)
+ {
+ if (freeAtomHeader(btrt->atomhdr) < 0)
+ return -1;
+
+ mp4free(btrt);
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeM4DS(mpeg4ExtensionDescriptorsAtom *m4ds)
+ *
+ * Description:
+ *
+ * This function frees memory for m4ds atom.
+ *
+ * Parameters:
+ *
+ * m4ds m4ds atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeM4DS(mpeg4ExtensionDescriptorsAtom *m4ds)
+{
+ if (m4ds)
+ {
+ if (freeAtomHeader(m4ds->atomhdr) < 0)
+ return -1;
+ if(m4ds->descr)
+ mp4free(m4ds->descr);
+
+ mp4free(m4ds);
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeAVC1(avcSampleEntry *avc1)
+ *
+ * Description:
+ *
+ * This function frees memory for avc1 atom.
+ *
+ * Parameters:
+ *
+ * avc1 avc1 atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeAVC1(avcSampleEntry *avc1)
+{
+ if (avc1)
+ {
+ if (freeAtomHeader(avc1->atomhdr) < 0)
+ return -1;
+ if (freeAVCC(avc1->avcc) < 0)
+ return -1;
+ if (freeBTRT(avc1->btrt) < 0)
+ return -1;
+ if (freeM4DS(avc1->m4ds) < 0)
+ return -1;
+
+ mp4free(avc1);
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSQCP(MP4HandleImp handle,
+ * qcelpSampleEntry *sqcp)
+ *
+ * Description:
+ *
+ * This function parses one SQCP atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * sqcp SQCP pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSQCP(MP4HandleImp handle, qcelpSampleEntry *sqcp)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((sqcp->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, sqcp->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (sqcp->atomhdr->type != ATOMTYPE_SQCP)
+ return -1;
+
+
+ bytesread = discardData(handle, 6);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ sqcp->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 16);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 2);
+ if (bytesread < 0)
+ return -1;
+ sqcp->timeScale = u16endian(*((mp4_u16 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = discardData(handle, 2);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ((sqcp->dqcp = (qcelpDecSpecStruc *)mp4malloc(sizeof(qcelpDecSpecStruc))) == NULL)
+ return -100;
+
+ bytesread = readDQCP(handle, sqcp->dqcp);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if ( totalbytesread < sqcp->atomhdr->size )
+ {
+ bytesread = discardData(handle, sqcp->atomhdr->size - totalbytesread );
+ if (bytesread < 0)
+ {
+ return -1;
+ }
+ totalbytesread += bytesread;
+ }
+
+ return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeSQCP(qcelpSampleEntry *sqcp)
+ *
+ * Description:
+ *
+ * This function frees memory for SQCP atom.
+ *
+ * Parameters:
+ *
+ * sqcp SQCP atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeSQCP(qcelpSampleEntry *sqcp)
+{
+ if (sqcp)
+ {
+ if (freeAtomHeader(sqcp->atomhdr) < 0)
+ return -1;
+ if (freeDQCP(sqcp->dqcp) < 0)
+ return -1;
+
+ mp4free(sqcp);
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 readDQCP(MP4HandleImp handle,
+ * qcelpDecSpecStruc *dqcp)
+ *
+ * Description:
+ *
+ * This function parses one DQCP atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * dqcp DQCP pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readDQCP(MP4HandleImp handle, qcelpDecSpecStruc *dqcp)
+{
+ mp4_i32 bytesread;
+ mp4_i32 totalbytesread = 0;
+
+
+ if ((dqcp->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, dqcp->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (dqcp->atomhdr->type != ATOMTYPE_DQCP)
+ return -1;
+
+
+ bytesread = readData(handle, handle->buf, 4);
+ if (bytesread < 0)
+ return -1;
+ dqcp->vendor = u32endian(*((mp4_u32 *)handle->buf));
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ dqcp->decoderVersion = handle->buf[0];
+ totalbytesread += bytesread;
+
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+ dqcp->framesPerSample = handle->buf[0];
+ totalbytesread += bytesread;
+
+ return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 freeDQCP(qcelpDecSpecStruc *dqcp)
+ *
+ * Description:
+ *
+ * This function frees memory for DQCP atom.
+ *
+ * Parameters:
+ *
+ * damr DQCP atom pointer
+ *
+ * Return value:
+ *
+ * 0 Success
+ * Negative Error
+ *
+ */
+mp4_i32 freeDQCP(qcelpDecSpecStruc *dqcp)
+{
+ if (dqcp)
+ {
+ if (freeAtomHeader(dqcp->atomhdr) < 0)
+ return -1;
+
+ mp4free(dqcp);
+ }
+
+ return 0;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 readSDTP(MP4HandleImp handle, sampleDependencyAtom *sdtp,
+ * mp4_i32 sample_count)
+ *
+ * Description:
+ *
+ * This function parses one SDTP atom.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * sdtp SDTP atom pointer
+ *
+ * Return value:
+ *
+ * Negative integer Error
+ * >= 0 Success. Value tells how many bytes were read.
+ *
+ */
+
+mp4_i32 readSDTP(MP4HandleImp handle,
+ sampleDependencyAtom *sdtp,
+ mp4_i32 sample_count)
+{
+ mp4_i32 bytesread = 0;
+ mp4_i32 totalbytesread = 0;
+ mp4_u32 i = 0;
+
+ if ((sdtp->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+ return -100;
+
+ bytesread = readAtomHeader(handle, sdtp->atomhdr);
+ if (bytesread < 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ if (sdtp->atomhdr->type != ATOMTYPE_SDTP)
+ return -1;
+
+ bytesread = readData(handle, handle->buf, 1); //Version must be 0
+ if (bytesread < 0 || handle->buf[0] != 0)
+ return -1;
+ totalbytesread += bytesread;
+ bytesread = readData(handle, handle->buf, 3); // Flags must be 0
+ if (bytesread < 0 || handle->buf[0] != 0 || handle->buf[1] != 0 || handle->buf[2] != 0)
+ return -1;
+ totalbytesread += bytesread;
+
+ // sample_count == (size_of_atom - 12) ??? 12 = size + 'sdtp' + ver + flags = 4 + 4 + 1 + 3 ???
+ //
+ // sample_count is taken from the sample_count in the Sample Size Box ('stsz') or
+ // Compact Sample Size Box (‘stz2’).
+ if (sample_count != sdtp->atomhdr->size-12 || sample_count < 0)
+ {
+ // as each byte consititue one entry in the table, the number of remaining bytes in this
+ // atom should match the sample count. If not, the file is corrupted.
+ return -1;
+ }
+
+ if ((sdtp->dep = (sampleDependency *)mp4malloc(sample_count * sizeof(sampleDependency))) == NULL)
+ return -100;
+
+ for(i=0;i<sample_count;i++)
+ {
+ bytesread = readData(handle, handle->buf, 1);
+ if (bytesread < 0)
+ return -1;
+
+ sdtp->dep[i].sDependsOn = (handle->buf[0] >> 4) & 0x03; // value from 0 to 3
+ sdtp->dep[i].sIsDependentOn = (handle->buf[0] >> 2) & 0x03; // value from 0 to 3
+ sdtp->dep[i].sHasRedundancy = handle->buf[0] & 0x03; // value from 0 to 3
+ totalbytesread += bytesread;
+ }
+
+ sdtp->sampleCount = sample_count;
+ return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ * mp4_i32 readBoxHeader(MP4HandleImp handle, mp4_i64* size, mp4_u32* type)
+ *
+ *
+ * Description:
+ *
+ * This function parses the size and type information for a box.
+ * Taking into account largesize if needed.
+ *
+ * Parameters:
+ *
+ * handle MP4 library handle
+ * size Size of box is returned here
+ * type Type of the box is returned here
+ * Return value:
+ *
+ * Negative integer Error
+ * 0 Success.
+ *
+ */
+mp4_i32 readBoxHeader(MP4HandleImp handle, mp4_i64* size, mp4_u32* type)
+{
+ if (peekData(handle, handle->buf, 8) < 0)
+ return -1;
+
+ *size = u32endian(*((mp4_u32 *)handle->buf));
+ *type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ if (*size == 1)
+ {
+ if (peekData(handle, handle->buf, 16) < 0)
+ return -1;
+
+ *size = u64endian(*((mp4_u64 *)(handle->buf+8)));
+ }
+
+ return 0;
+}
+
+/*
+ */
+
+mp4_i64 getChunkOffset(sampleTableAtom *stbl, mp4_u32 index)
+{
+ if (stbl->is32BitOffsets)
+ return (mp4_i64)stbl->stco->chunkOffset[index];
+ else
+ return stbl->stco64->chunkOffset[index];
+}
+
+// End of File