diff -r 000000000000 -r bde4ae8d615e os/mm/mmplugins/lib3gp/impl/src/atom.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/mm/mmplugins/lib3gp/impl/src/atom.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,9143 @@ +// 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 +//#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; + } + + case ATOMTYPE_META: + + { + if (moov->meta) /* META has already been read, more than one is not allowed */ + return -1; + + if ((moov->meta = (metaAtom *)mp4malloc(sizeof(metaAtom))) == NULL) + return -100; + + bytesread = readMeta(handle, moov->meta); + 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; + if (freeMETA(moov->meta) < 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;ibuf, 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]; +} + +/* + * Function: + * + * mp4_i32 readMeta(MP4HandleImp handle, + * metaAtom *meta) + * + * Description: + * + * This function parses one META atom. + * + * Parameters: + * + * handle MP4 library handle + * meta META pointer + * + * Return value: + * + * Negative integer Error + * >= 0 Success. Value tells how many bytes were read. + * + */ +mp4_i32 readMeta(MP4HandleImp handle, metaAtom *meta) +{ + mp4_i32 bytesread; + mp4_i32 totalbytesread = 0; + + + if ((meta->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL) + return -100; + + bytesread = readFullAtomHeader(handle, meta->atomhdr); + if (bytesread < 0) + return -1; + totalbytesread += bytesread; + + if (meta->atomhdr->type != ATOMTYPE_META) + return -1; + + + while ((mp4_u32)totalbytesread < meta->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_HDLR: + + if (meta->hdlr) /* HDLR has already been read, more than one is not allowed */ + return -1; + + if ((meta->hdlr = (handlerAtom *)mp4malloc(sizeof(handlerAtom))) == NULL) + return -100; + + bytesread = readHDLR(handle, meta->hdlr); + if (bytesread < 0) + return -1; + totalbytesread += bytesread; + + break; + + case ATOMTYPE_ID32: + + if (meta->ID32) /* ID32 has already been read, more than one is not allowed */ + return -1; + + if ((meta->ID32 = (ID32Atom *)mp4malloc(sizeof(ID32Atom))) == NULL) + return -100; + + bytesread = readID32(handle, meta->ID32); + 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 readID32(MP4HandleImp handle, + * ID32Atom *ID32) + * + * Description: + * + * This function parses one ID32 atom. + * + * Parameters: + * + * handle MP4 library handle + * ID32 ID32 pointer + * + * Return value: + * + * Negative integer Error + * >= 0 Success. Value tells how many bytes were read. + * + */ +mp4_i32 readID32(MP4HandleImp handle, ID32Atom *ID32) +{ + mp4_i32 bytesread; + mp4_i32 totalbytesread = 0; + + + if ((ID32->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL) + return -100; + + bytesread = readFullAtomHeader(handle, ID32->atomhdr); + if (bytesread < 0) + return -1; + totalbytesread += bytesread; + + if (ID32->atomhdr->type != ATOMTYPE_ID32) + return -1; + + // next 2 bytes: top bit is padding, remaining 15 bits is Packed ISO-639-2/T language code + bytesread = readData(handle, handle->buf, 2); + if (bytesread < 0) + return -1; + ID32->language = u16endian(*((mp4_u16 *)handle->buf)); + totalbytesread += bytesread; + + if ( handle->file ) + { + ID32->atomcontentloc = handle->diskReadBufStart + handle->diskReadBufPos; + } + else + { + ID32->atomcontentloc = handle->absPosition; + } + + bytesread = discardData(handle, ID32->atomhdr->size - totalbytesread ); + if (bytesread < 0) + return -1; + totalbytesread += bytesread; + + return totalbytesread; +} + +/* + * Function: + * + * mp4_i32 freeMETA(metaAtom *meta) + * + * Description: + * + * This function frees memory for META atom. + * + * Parameters: + * + * meta META atom pointer + * + * Return value: + * + * 0 Success + * Negative Error + * + */ +mp4_i32 freeMETA(metaAtom *meta) +{ + if (meta) + { + if (freeAtomHeader(meta->atomhdr) < 0) + return -1; + if (freeHDLR(meta->hdlr) < 0) + return -1; + if (freeID32(meta->ID32) < 0) + return -1; + + mp4free(meta); + } + + return 0; +} + +/* + * Function: + * + * mp4_i32 freeID32(ID32Atom *ID32) + * + * Description: + * + * This function frees memory for ID32 atom. + * + * Parameters: + * + * ID32 ID32 atom pointer + * + * Return value: + * + * 0 Success + * Negative Error + * + */ +mp4_i32 freeID32(ID32Atom *ID32) +{ + if (ID32) + { + if (freeAtomHeader(ID32->atomhdr) < 0) + return -1; + + mp4free(ID32); + } + + return 0; +} +// End of File