os/mm/mmplugins/lib3gp/impl/src/atom.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include <3gplibrary/mp4config.h>
    17 #include <3gplibrary/mp4lib.h>
    18 #include "mp4atom.h"
    19 #include "mp4memwrap.h"
    20 #include "mp4buffer.h"
    21 #include "mp4endian.h"
    22 #include "mp4file.h"
    23 #include "mp4utils.h"
    24 
    25 // MACROS
    26 // Debug print macro
    27 #ifdef _DEBUG
    28 #include <e32svr.h>
    29 //#define PRINT(x) RDebug::Print x
    30 #define PRINT(x)
    31 #else
    32 #define PRINT(x)
    33 #endif
    34 
    35 mp4_i32 readBoxHeader(MP4HandleImp handle, mp4_i64* size, mp4_u32* type);
    36  
    37 /*
    38  * Function:
    39  *
    40  *   mp4_i32 metaDataAvailable(MP4HandleImp handle)
    41  *
    42  * Description:
    43  *
    44  *   This function determines whether meta data is available for reading
    45  *   or not.
    46  *
    47  *   Meta data is available if the input is in a file.
    48  *
    49  *   When reading from a stream, meta data is considered available if
    50  *   it is in the beginning of the stream and the entire Moov atom has
    51  *   been received. FTYP atom is allowed before MOOV atom.
    52  *
    53  * Parameters:
    54  *
    55  *   handle   MP4 library handle
    56  *
    57  * Return value:
    58  *
    59  *   0                Meta data is not available because enough data has not
    60  *                    been inserted into the library
    61  *   1                Meta data is available
    62  *   Negative value   Meta data is not available because of fatal error
    63  *
    64  */
    65 mp4_i32 metaDataAvailable(MP4HandleImp handle)
    66 {
    67   mp4_u32 size;
    68   mp4_u32 type;
    69 
    70 
    71   /* Meta data is available if the input is in a file or if a complete file has been inputted as a stream*/
    72 
    73   if (handle->file)
    74     return 1;
    75 
    76   /* When reading from a stream, meta data is considered available if
    77      it is in the beginning of the stream and the entire MOOV atom has
    78      been received. FTYP atom is allowed before MOOV atom. */
    79 
    80   if (!handle->ftypRead)
    81   {
    82     if (peekData(handle, handle->buf, 8) < 0) /* 8 bytes are not available */
    83         return 0;
    84 
    85     size = u32endian(*((mp4_u32 *)handle->buf));
    86     type = u32endian(*((mp4_u32 *)(handle->buf+4)));
    87 
    88     if (type == ATOMTYPE_FTYP)
    89     {
    90       if (getBufferedBytes(handle) - handle->position < size) /* FTYP is not available */
    91         return 0;
    92       if ((handle->ftyp = (fileTypeAtom *)mp4malloc(sizeof(fileTypeAtom))) == NULL)
    93         return -100;
    94       if (readFTYP(handle, handle->ftyp) < 0)
    95         return -2;
    96     }
    97   }
    98 
    99   // Now the ftyp is read. No need to chedk MOOV presence for full files in the memory.
   100   if (handle->LastWriteDataCalled == MP4TRUE)
   101       return 1;
   102 
   103   if (handle->LastWriteDataCalled == MP4FALSE)
   104   {//Whole stream is not fed to the internal memory yet. 
   105    for (;;)
   106     {
   107       if (peekData(handle, handle->buf, 8) < 0)
   108         return 0;
   109 
   110       size = u32endian(*((mp4_u32 *)handle->buf));
   111       type = u32endian(*((mp4_u32 *)(handle->buf+4)));
   112 
   113       if (type == ATOMTYPE_MOOV)
   114         {
   115         if (getBufferedBytes(handle) - handle->absPosition >= size) /* Entire Moov is available */
   116             {
   117             return 1;        
   118             }
   119         else
   120             {
   121             return 0;
   122             }
   123         }
   124 
   125       if ((mp4_i32)size <= 0)
   126         return -1;
   127 
   128       handle->absPosition+=size;
   129     }
   130   }
   131   return 0;
   132 }
   133 
   134 
   135 /*
   136  * Function:
   137  *
   138  *   mp4_i32 readFTYP(MP4HandleImp handle,
   139  *                    fileTypeAtom *ftyp)
   140  *
   141  * Description:
   142  *
   143  *   This function parses one FTYP atom.
   144  *
   145  * Parameters:
   146  *
   147  *   handle             MP4 library handle
   148  *   ftyp               FTYP pointer
   149  *
   150  * Return value:
   151  *
   152  *   Negative integer   Error
   153  *   >= 0               Success. Value tells how many bytes were read.
   154  *
   155  */
   156 mp4_i32 readFTYP(MP4HandleImp handle, fileTypeAtom *ftyp)
   157 {
   158   mp4_i32 bytesread;
   159   mp4_i32 totalbytesread = 0;
   160   mp4_u32 n = 0;
   161   mp4_i32 compatiblebrandsize = 0;
   162 
   163 
   164   if ((ftyp->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
   165     return -100;
   166 
   167   bytesread = readAtomHeader(handle, ftyp->atomhdr);
   168   if (bytesread < 0)
   169     return -1;
   170   totalbytesread += bytesread;
   171 
   172   if (ftyp->atomhdr->type != ATOMTYPE_FTYP)
   173     return -1;
   174 
   175   if (ftyp->atomhdr->size < 16) // 8(header)+8bytes needed for major and minor brand
   176     return -1;
   177 
   178   bytesread = readData(handle, handle->buf, 4);
   179   if (bytesread < 0)
   180     return -1;
   181   ftyp->majorBrand = u32endian(*((mp4_u32 *)handle->buf));
   182   totalbytesread += bytesread;
   183 
   184   bytesread = readData(handle, handle->buf, 4);
   185   if (bytesread < 0)
   186     return -1;
   187   ftyp->minorVersion = u32endian(*((mp4_u32 *)handle->buf));
   188   totalbytesread += bytesread;
   189 
   190   if (ftyp->atomhdr->size == (mp4_u32)totalbytesread)
   191     return totalbytesread;
   192 
   193   compatiblebrandsize = (mp4_i32)ftyp->atomhdr->size - totalbytesread;
   194   if ( compatiblebrandsize < 4 )   // at this point we must have at least 1 compatible brand
   195     return -1;
   196   if ( compatiblebrandsize > 20*4) // maximum of 20 compatible brands 4byte entries
   197     return -1;
   198   if ( compatiblebrandsize % 4 ) // must be able to divide by 4
   199     return -1;
   200 
   201   ftyp->compatibleBrands = (mp4_u32 *)mp4malloc( compatiblebrandsize );
   202   if (ftyp->compatibleBrands == NULL)
   203     return -1;
   204 
   205   while ((mp4_u32)totalbytesread < ftyp->atomhdr->size)
   206   {
   207     bytesread = readData(handle, handle->buf, 4);
   208     if (bytesread < 0)
   209       return -1;
   210 
   211     ftyp->compatibleBrands[n] = u32endian(*((mp4_u32 *)handle->buf));
   212 
   213     n++;
   214     totalbytesread += bytesread;
   215   }
   216 
   217   return totalbytesread;
   218 }
   219 
   220 
   221 /*
   222  * Function:
   223  *
   224  *   mp4_i32 readMetaData(MP4HandleImp handle)
   225  *
   226  * Description:
   227  *
   228  *   This function reads the meta data from the file/stream and stores
   229  *   the information in the atom structures available via handle.
   230  *
   231  * Parameters:
   232  *
   233  *   handle  MP4 library handle
   234  *
   235  * Return value:
   236  *
   237  *   Negative value   Error
   238  *   >= 0             Success. Value tells the number of bytes read.
   239  *
   240  */
   241 mp4_i32 readMetaData(MP4HandleImp handle)
   242 {
   243   mp4_i32 bytesread;
   244   mp4_i32 totalbytesread = 0;
   245 
   246 
   247   if (handle->file)
   248   {
   249     mp4_u64 size;
   250     mp4_u32 type;
   251 
   252 
   253     if (seekFileAbs(handle, 0) < 0)
   254       return -1;
   255 
   256     /* Seek to the start of FTYP atom */
   257 
   258     for (;;)
   259     {
   260       if (readBoxHeader(handle, &size, &type) <0)
   261         return -1;
   262 
   263       if (type == ATOMTYPE_FTYP)
   264       {
   265         /* Read FTYP */
   266 
   267         if ((handle->ftyp = (fileTypeAtom *)mp4malloc(sizeof(fileTypeAtom))) == NULL)
   268           return -100;
   269         bytesread = readFTYP(handle, handle->ftyp);
   270         if (bytesread < 0)
   271           return -3;
   272         totalbytesread += bytesread;
   273 
   274         break;
   275       }
   276 
   277       if (size <= 0)
   278         return -1;
   279 
   280       if (seekFile(handle, size) != 0)
   281         return -1;
   282     }
   283 
   284     if (seekFileAbs(handle, 0) < 0)
   285       return -1;
   286 
   287     /* Seek to the start of MOOV atom */
   288     for (;;)
   289     {
   290       if (readBoxHeader(handle, &size, &type) <0)
   291         return -1;
   292 
   293       if (type == ATOMTYPE_MOOV)
   294         break;
   295 
   296       if (size <= 0)
   297         return -1;
   298 
   299       if (seekFile(handle, size) != 0)
   300         return -1;
   301     }
   302   }
   303 
   304   // If all data of a file is in the memory and the file does not have MOOV box right after FTYP, 
   305   // then we need to seek for the location of the MOOV first
   306 
   307   if (handle->LastWriteDataCalled == MP4TRUE)
   308   { 
   309     mp4_u32 size;
   310     mp4_u32 type;
   311     // Seek until the beginning of MOOV box.
   312     for(;;)
   313     {
   314         if (peekData(handle, handle->buf, 8) < 0)
   315             return -1;
   316 
   317         size = u32endian(*((mp4_u32 *)handle->buf));
   318         type = u32endian(*((mp4_u32 *)(handle->buf+4)));
   319     
   320         if (type == ATOMTYPE_MOOV)
   321           break;
   322 
   323         if ((mp4_i32)size <= 0)
   324           return -1;
   325 
   326         if (discardData(handle, size) < 0)
   327           return -1;
   328     }
   329   }
   330 
   331   if ((handle->moov = (movieAtom *)mp4malloc(sizeof(movieAtom))) == NULL)
   332     return -100;
   333 
   334   bytesread = readMoov(handle, handle->moov);
   335   if (bytesread < 0)
   336     return -3;
   337   totalbytesread += bytesread;
   338 
   339   if (handle->moov->trakAudio)
   340   {
   341     mp4_u32 audiotype;
   342 	mp4_i32 errorAudio = 0;
   343 
   344 	errorAudio = determineAudioType(handle, &audiotype);
   345     if ( errorAudio == 0 )
   346     {
   347 	   	handle->type |= audiotype;    	
   348     
   349 	    /* Move to the beginning of the 1st audio frame */
   350 	    switch (advanceAudioSample(handle, handle->moov->trakAudio))
   351 	    {
   352 	    case -1:
   353 	      return -1;
   354 	    case -2:
   355 	      handle->audioLast = MP4TRUE;
   356 	      break;
   357 	    default:
   358 	      break;
   359 	    }
   360 	}
   361 	else if (errorAudio == -2)
   362 	{
   363 		handle->type |= audiotype;	
   364 	}
   365 	else
   366 	{
   367 		return -1;
   368 	}
   369   }
   370 
   371   if (handle->moov->trakVideo)
   372   {
   373     mp4_u32 videotype;
   374     mp4_i32 errorVideo = 0;
   375 
   376 	errorVideo = determineVideoType(handle, &videotype);
   377     if ( errorVideo == 0 )
   378     {
   379 	   	handle->type |= videotype;    	
   380     
   381     	/* Move to the beginning of the 1st video frame */
   382 	    switch (advanceVideoFrame(handle, handle->moov->trakVideo))
   383 	    {
   384 	    case -1:
   385 	      return -1;
   386 	    case -2:
   387 	       handle->videoLast = MP4TRUE;
   388 	      break;
   389 	    default:
   390 	      break;
   391 	    }
   392 	}
   393 	else if (errorVideo == -2)
   394 	{
   395 	   	handle->type |= videotype;	
   396 	}
   397 	else
   398 	{
   399 		return -1;
   400 	}
   401   }
   402 
   403   return totalbytesread;
   404 }
   405 
   406 
   407 /*
   408  * Function:
   409  *
   410  *   mp4_i32 readMoov(MP4HandleImp handle,
   411  *                    movieAtom *moov)
   412  *
   413  * Description:
   414  *
   415  *   This function parses one MOOV atom.
   416  *
   417  * Parameters:
   418  *
   419  *   handle             MP4 library handle
   420  *   moov               MOOV pointer
   421  *
   422  * Return value:
   423  *
   424  *   Negative integer   Error
   425  *   >= 0               Success. Value tells how many bytes were read.
   426  *
   427  */
   428 mp4_i32 readMoov(MP4HandleImp handle, movieAtom *moov)
   429 {
   430   mp4_i32 bytesread;
   431   mp4_i32 totalbytesread = 0;
   432 
   433 
   434   if ((moov->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
   435     return -100;
   436 
   437   bytesread = readAtomHeader(handle, moov->atomhdr);
   438   if (bytesread < 0)
   439     return -1;
   440   totalbytesread += bytesread;
   441 
   442   if (moov->atomhdr->type != ATOMTYPE_MOOV)
   443     return -1;
   444 
   445   while ((mp4_u32)totalbytesread < handle->moov->atomhdr->size)
   446   {
   447     mp4_u32 type;
   448 
   449 
   450     if (peekData(handle, handle->buf, 8) < 0)
   451       return -1;
   452 
   453     type = u32endian(*((mp4_u32 *)(handle->buf+4)));
   454 
   455     switch (type)
   456     {
   457     case ATOMTYPE_MVHD:
   458 
   459       if (moov->mvhd) /* MVHD has already been read, more than one is not allowed */
   460         return -1;
   461 
   462       if ((moov->mvhd = (movieHeaderAtom *)mp4malloc(sizeof(movieHeaderAtom))) == NULL)
   463         return -100;
   464 
   465       bytesread = readMVHD(handle, moov->mvhd);
   466       if (bytesread < 0)
   467         return -1;
   468       totalbytesread += bytesread;
   469 
   470       break;
   471 
   472     case ATOMTYPE_IODS:
   473 
   474       if (moov->iods) /* IODS has already been read, more than one is not allowed */
   475         return -1;
   476 
   477       if ((moov->iods = (objectDescriptorAtom *)mp4malloc(sizeof(objectDescriptorAtom))) == NULL)
   478         return -100;
   479 
   480       bytesread = readIODS(handle, moov->iods);
   481       if (bytesread < 0)
   482         return -1;
   483       totalbytesread += bytesread;
   484 
   485       break;
   486 
   487     case ATOMTYPE_TRAK:
   488 
   489       {
   490         trackAtom *ta;
   491 
   492         if ((ta = (trackAtom *)mp4malloc(sizeof(trackAtom))) == NULL)
   493           return -100;
   494 
   495         bytesread = readTRAK(handle, ta);
   496         if (bytesread < 0)
   497         {
   498           if (freeTRAK(ta) < 0)
   499             return -1;
   500           return -1;
   501         }
   502         totalbytesread += bytesread;
   503 
   504         if (!ta->mdia)
   505         {
   506           if (freeTRAK(ta) < 0)
   507             return -1;
   508           return -1;
   509         }
   510         if (!ta->mdia->hdlr)
   511         {
   512           if (freeTRAK(ta) < 0)
   513             return -1;
   514           return -1;
   515         }
   516 
   517         if (ta->mdia->hdlr->handlerType != HANDLERTYPE_VIDE &&
   518             ta->mdia->hdlr->handlerType != HANDLERTYPE_SOUN) /* Track is neither video nor audio */
   519         {
   520           /* Do nothing with the unknown track */
   521           if (freeTRAK(ta) < 0)
   522             return -1;
   523           break;
   524         }
   525 
   526         if (ta->mdia->hdlr->handlerType == HANDLERTYPE_VIDE)
   527         {
   528 	        if (moov->trakVideo) /* Video Track already read */
   529 	        {
   530 	          if (freeTRAK(ta) < 0)
   531 	            return -1;
   532 	        }
   533 	        else
   534 	        {
   535 	          moov->trakVideo = ta;
   536 	        }
   537         }
   538 		else if (ta->mdia->hdlr->handlerType == HANDLERTYPE_SOUN)
   539         {
   540 	        if (moov->trakAudio) /* Audio Track already read */
   541 	        {
   542 	          if (freeTRAK(ta) < 0)
   543 	            return -1;
   544 	        }
   545 	        else
   546 	        {
   547 	          moov->trakAudio = ta;
   548 	        }
   549         }
   550         else
   551         {
   552         }
   553         break;
   554       }
   555 
   556     case ATOMTYPE_UDTA:
   557 
   558       {
   559       if (moov->udta) /* UDTA has already been read */
   560           {
   561           bytesread = readUnknown(handle);
   562           if (bytesread < 0)
   563             return -1;
   564           totalbytesread += bytesread;
   565           break;
   566           }
   567 
   568 
   569       if ((moov->udta = (userDataAtom *)mp4malloc(sizeof(userDataAtom))) == NULL)
   570         return -100;
   571 
   572       bytesread = readUDTA(handle, moov->udta);
   573       if (bytesread < 0)
   574         return -1;
   575       totalbytesread += bytesread;
   576 
   577       break;
   578       }
   579       
   580     case ATOMTYPE_META:
   581         
   582         {
   583         if (moov->meta) /* META has already been read, more than one is not allowed */
   584           return -1;
   585            
   586         if ((moov->meta = (metaAtom *)mp4malloc(sizeof(metaAtom))) == NULL)
   587             return -100;
   588 
   589         bytesread = readMeta(handle, moov->meta);
   590         if (bytesread < 0)
   591           return -1;
   592         totalbytesread += bytesread;
   593         
   594         break;
   595         }
   596         
   597     default:
   598 
   599       bytesread = readUnknown(handle);
   600       if (bytesread < 0)
   601         return -1;
   602       totalbytesread += bytesread;
   603 
   604       break;
   605     }
   606   }
   607 
   608   return totalbytesread;
   609 }
   610 
   611 
   612 /*
   613  * Function:
   614  *
   615  *   mp4_i32 readAtomheader(MP4HandleImp handle,
   616  *                          atomHeader *ah)
   617  *
   618  * Description:
   619  *
   620  *   This function reads an atom header and stores the information
   621  *   in ah.
   622  *
   623  * Parameters:
   624  *
   625  *   handle           MP4 library handle
   626  *   ah               atomHeader structure that is used to store the
   627  *                    information
   628  *
   629  * Return value:
   630  *
   631  *   Negative value   Error
   632  *   >= 0             Success. Value tells how many bytes were read.
   633  *
   634  */
   635 mp4_i32 readAtomHeader(MP4HandleImp handle, atomHeader *ah)
   636 {
   637   mp4_i32 bytesread;
   638   mp4_i32 totalbytesread = 0;
   639 
   640   //PRINT((_L("readAtomHeader")));
   641   bytesread = readData(handle, handle->buf, 4);
   642   if (bytesread < 0)
   643     return -1;
   644   ah->size = u32endian(*((mp4_u32 *)handle->buf));
   645   totalbytesread += bytesread;
   646 
   647   bytesread = readData(handle, handle->buf, 4);
   648   if (bytesread < 0)
   649     return -1;
   650   ah->type = u32endian(*((mp4_u32 *)handle->buf));
   651   totalbytesread += bytesread;
   652 
   653   if (ah->size == 1)
   654   {
   655     bytesread = readData(handle, handle->buf, 8);
   656     if (bytesread < 0)
   657       return -1;
   658     ah->largeSize = u64endian(*((mp4_u64 *)handle->buf));
   659     totalbytesread += bytesread;
   660   }
   661 
   662   if (ah->type == ATOMTYPE_UUID)
   663   {
   664     bytesread = readData(handle, handle->buf, 16);
   665     if (bytesread < 0)
   666       return -1;
   667     mp4memcpy(ah->extendedType, handle->buf, 16);
   668     totalbytesread += bytesread;
   669   }
   670 
   671   //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]));
   672   return totalbytesread;
   673 }
   674 
   675 
   676 /*
   677  * Function:
   678  *
   679  *   mp4_i32 readFullAtomHeader(MP4HandleImp handle,
   680  *                              atomHeader *ah)
   681  *
   682  * Description:
   683  *
   684  *   This function reads a full atom header and stores the information
   685  *   in ah.
   686  *
   687  * Parameters:
   688  *
   689  *   handle           MP4 library handle
   690  *   ah               atomHeader structure that is used to store the
   691  *                    information
   692  *
   693  * Return value:
   694  *
   695  *   Negative value   Error
   696  *   >= 0             Success. Value tells how many bytes were read.
   697  *
   698  */
   699 mp4_i32 readFullAtomHeader(MP4HandleImp handle, atomHeader *ah)
   700 {
   701   mp4_i32 bytesread;
   702   mp4_i32 totalbytesread = 0;
   703 
   704   //PRINT((_L("readFullAtomHeader")));
   705 
   706   bytesread = readData(handle, handle->buf, 4);
   707   if (bytesread < 0)
   708     return -1;
   709   ah->size = u32endian(*((mp4_u32 *)handle->buf));
   710   totalbytesread += bytesread;
   711 
   712   bytesread = readData(handle, handle->buf, 4);
   713   if (bytesread < 0)
   714     return -1;
   715   ah->type = u32endian(*((mp4_u32 *)handle->buf));
   716   totalbytesread += bytesread;
   717 
   718   bytesread = readData(handle, handle->buf, 1);
   719   if (bytesread < 0)
   720     return -1;
   721   ah->version = *(handle->buf);
   722   totalbytesread += bytesread;
   723 
   724   bytesread = readData(handle, handle->buf, 3);
   725   if (bytesread < 0)
   726     return -1;
   727   mp4memcpy(ah->flags, handle->buf, 3);
   728   totalbytesread += bytesread;
   729 
   730   //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]));
   731   return totalbytesread;
   732 }
   733 
   734 
   735 /*
   736  * Function:
   737  *
   738  *   mp4_i32 readMVHD(MP4HandleImp handle,
   739  *                    movieHeaderAtom *mvhd)
   740  *
   741  * Description:
   742  *
   743  *   This function parses one MVHD atom.
   744  *
   745  * Parameters:
   746  *
   747  *   handle             MP4 library handle
   748  *   mvhd               MVHD pointer
   749  *
   750  * Return value:
   751  *
   752  *   Negative integer   Error
   753  *   >= 0               Success. Value tells how many bytes were read.
   754  *
   755  */
   756 mp4_i32 readMVHD(MP4HandleImp handle, movieHeaderAtom *mvhd)
   757 {
   758   mp4_i32 bytesread;
   759   mp4_i32 totalbytesread = 0;
   760 
   761 
   762   if ((mvhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
   763     return -100;
   764 
   765   bytesread = readFullAtomHeader(handle, mvhd->atomhdr);
   766   if (bytesread < 0)
   767     return -1;
   768   totalbytesread += bytesread;
   769 
   770   if (mvhd->atomhdr->type != ATOMTYPE_MVHD)
   771     return -1;
   772 
   773   if (mvhd->atomhdr->version == 1) /* 64 bit */
   774   {
   775     bytesread = readData(handle, handle->buf, 8);
   776     if (bytesread < 0)
   777       return -1;
   778     mvhd->creationTime64 = u64endian(*((mp4_u64 *)handle->buf));
   779     totalbytesread += bytesread;
   780 
   781     bytesread = readData(handle, handle->buf, 8);
   782     if (bytesread < 0)
   783       return -1;
   784     mvhd->modificationTime64 = u64endian(*((mp4_u64 *)handle->buf));
   785     totalbytesread += bytesread;
   786 
   787     bytesread = readData(handle, handle->buf, 4);
   788     if (bytesread < 0)
   789       return -1;
   790     mvhd->timeScale = u32endian(*((mp4_u32 *)handle->buf));
   791     totalbytesread += bytesread;
   792 
   793     bytesread = readData(handle, handle->buf, 8);
   794     if (bytesread < 0)
   795       return -1;
   796     mvhd->duration64 = u64endian(*((mp4_u64 *)handle->buf));
   797     totalbytesread += bytesread;
   798   }
   799   else /* 32 bit */
   800   {
   801     bytesread = readData(handle, handle->buf, 4);
   802     if (bytesread < 0)
   803       return -1;
   804     mvhd->creationTime = u32endian(*((mp4_u32 *)handle->buf));
   805     totalbytesread += bytesread;
   806 
   807     bytesread = readData(handle, handle->buf, 4);
   808     if (bytesread < 0)
   809       return -1;
   810     mvhd->modificationTime = u32endian(*((mp4_u32 *)handle->buf));
   811     totalbytesread += bytesread;
   812 
   813     bytesread = readData(handle, handle->buf, 4);
   814     if (bytesread < 0)
   815       return -1;
   816     mvhd->timeScale = u32endian(*((mp4_u32 *)handle->buf));
   817     totalbytesread += bytesread;
   818 
   819     bytesread = readData(handle, handle->buf, 4);
   820     if (bytesread < 0)
   821       return -1;
   822     mvhd->duration = u32endian(*((mp4_u32 *)handle->buf));
   823     totalbytesread += bytesread;
   824   }
   825 
   826   bytesread = discardData(handle, 76);
   827   if (bytesread < 0)
   828     return -1;
   829   totalbytesread += bytesread;
   830 
   831   bytesread = readData(handle, handle->buf, 4);
   832   if (bytesread < 0)
   833     return -1;
   834   mvhd->nextTrackID = u32endian(*((mp4_u32 *)handle->buf));
   835   totalbytesread += bytesread;
   836 
   837   return totalbytesread;
   838 }
   839 
   840 
   841 /*
   842  * Function:
   843  *
   844  *   mp4_i32 readIODS(MP4HandleImp handle,
   845  *                    objectDescriptorAtom *iods)
   846  *
   847  * Description:
   848  *
   849  *   This function parses one IODS atom.
   850  *
   851  * Parameters:
   852  *
   853  *   handle             MP4 library handle
   854  *   iods               IODS pointer
   855  *
   856  * Return value:
   857  *
   858  *   Negative integer   Error
   859  *   >= 0               Success. Value tells how many bytes were read.
   860  *
   861  */
   862 mp4_i32 readIODS(MP4HandleImp handle, objectDescriptorAtom *iods)
   863 {
   864   mp4_i32 bytesread;
   865   mp4_i32 totalbytesread = 0;
   866 
   867 
   868   if ((iods->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
   869     return -100;
   870 
   871   bytesread = readFullAtomHeader(handle, iods->atomhdr);
   872   if (bytesread < 0)
   873     return -1;
   874   totalbytesread += bytesread;
   875 
   876   if (iods->atomhdr->type != ATOMTYPE_IODS)
   877     return -1;
   878 
   879   bytesread = discardData(handle, iods->atomhdr->size - totalbytesread);
   880   if (bytesread < 0)
   881     return -1;
   882   totalbytesread += bytesread;
   883 
   884   return totalbytesread;
   885 }
   886 
   887 
   888 /*
   889  * Function:
   890  *
   891  *   mp4_i32 readTRAK(MP4HandleImp handle,
   892  *                    trackAtom *trak)
   893  *
   894  * Description:
   895  *
   896  *   This function parses one TRAK atom.
   897  *
   898  * Parameters:
   899  *
   900  *   handle             MP4 library handle
   901  *   trak               TRAK pointer
   902  *
   903  * Return value:
   904  *
   905  *   Negative integer   Error
   906  *   >= 0               Success. Value tells how many bytes were read.
   907  *
   908  */
   909 mp4_i32 readTRAK(MP4HandleImp handle, trackAtom *trak)
   910 {
   911   mp4_i32 bytesread;
   912   mp4_i32 totalbytesread = 0;
   913 
   914 
   915   if ((trak->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
   916     return -100;
   917 
   918   bytesread = readAtomHeader(handle, trak->atomhdr);
   919   if (bytesread < 0)
   920     return -1;
   921   totalbytesread += bytesread;
   922 
   923   if (trak->atomhdr->type != ATOMTYPE_TRAK)
   924     return -1;
   925 
   926 
   927   while ((mp4_u32)totalbytesread < trak->atomhdr->size)
   928   {
   929     mp4_u32 type;
   930 
   931 
   932     if (peekData(handle, handle->buf, 8) < 0)
   933       return -1;
   934 
   935     type = u32endian(*((mp4_u32 *)(handle->buf+4)));
   936 
   937     switch (type)
   938     {
   939     case ATOMTYPE_TKHD:
   940 
   941       if (trak->tkhd) /* MVHD has already been read, more than one is not allowed */
   942         return -1;
   943 
   944       if ((trak->tkhd = (trackHeaderAtom *)mp4malloc(sizeof(trackHeaderAtom))) == NULL)
   945         return -100;
   946 
   947       bytesread = readTKHD(handle, trak->tkhd);
   948       if (bytesread < 0)
   949         return -1;
   950       totalbytesread += bytesread;
   951 
   952       break;
   953 
   954     case ATOMTYPE_TREF:
   955 
   956       if (trak->tref) /* TREF has already been read, more than one is not allowed */
   957         return -1;
   958 
   959       if ((trak->tref = (trackReferenceAtom *)mp4malloc(sizeof(trackReferenceAtom))) == NULL)
   960         return -100;
   961 
   962       bytesread = readTREF(handle, trak->tref);
   963       if (bytesread < 0)
   964         return -1;
   965       totalbytesread += bytesread;
   966 
   967       break;
   968 
   969     case ATOMTYPE_EDTS:
   970 
   971       if (trak->edts) /* EDTS has already been read, more than one is not allowed */
   972         return -1;
   973 
   974       if ((trak->edts = (editListContainerAtom *)mp4malloc(sizeof(editListContainerAtom))) == NULL)
   975         return -100;
   976 
   977       bytesread = readEDTS(handle, trak->edts);
   978       if (bytesread < 0)
   979         return -1;
   980       totalbytesread += bytesread;
   981 
   982       break;
   983 
   984     case ATOMTYPE_MDIA:
   985 
   986       if (trak->mdia) /* MDIA has already been read, more than one is not allowed */
   987         return -1;
   988 
   989       if ((trak->mdia = (mediaAtom *)mp4malloc(sizeof(mediaAtom))) == NULL)
   990         return -100;
   991 
   992       bytesread = readMDIA(handle, trak->mdia);
   993       if (bytesread < 0)
   994         return -1;
   995       totalbytesread += bytesread;
   996 
   997       break;
   998 
   999     case ATOMTYPE_UDTA:
  1000       {
  1001       if (trak->udta) /* UDTA has already been read */
  1002           {
  1003           bytesread = readUnknown(handle);
  1004           if (bytesread < 0)
  1005             return -1;
  1006           totalbytesread += bytesread;
  1007           break;
  1008           }
  1009 
  1010       if ((trak->udta = (userDataAtom *)mp4malloc(sizeof(userDataAtom))) == NULL)
  1011         return -100;
  1012 
  1013       bytesread = readUDTA(handle, trak->udta);
  1014       if (bytesread < 0)
  1015         return -1;
  1016       totalbytesread += bytesread;
  1017 
  1018       break;
  1019       }
  1020 
  1021     default:
  1022 
  1023       bytesread = readUnknown(handle);
  1024       if (bytesread < 0)
  1025         return -1;
  1026       totalbytesread += bytesread;
  1027 
  1028       break;
  1029     }
  1030   }
  1031 
  1032   return totalbytesread;
  1033 }
  1034 
  1035 
  1036 /*
  1037  * Function:
  1038  *
  1039  *   mp4_i32 readUnknown(MP4HandleImp handle)
  1040  *
  1041  * Description:
  1042  *
  1043  *   This function reads one atom of unknown type. Atom contents are
  1044  *   discarded.
  1045  *
  1046  * Parameters:
  1047  *
  1048  *   handle             MP4 library handle
  1049  *
  1050  * Return value:
  1051  *
  1052  *   Negative integer   Error
  1053  *   >= 0               Success. Value tells how many bytes were read.
  1054  *
  1055  */
  1056 mp4_i32 readUnknown(MP4HandleImp handle)
  1057 {
  1058   mp4_i32 bytesread;
  1059   mp4_i32 totalbytesread = 0;
  1060   mp4_u32 size;
  1061 
  1062 
  1063   bytesread = readData(handle, handle->buf, 4);
  1064   if (bytesread < 0)
  1065     return -1;
  1066   totalbytesread += bytesread;
  1067 
  1068   size = u32endian(*((mp4_u32 *)handle->buf));
  1069   if ( size < 4 )
  1070   {
  1071   	return -1;
  1072   }
  1073 
  1074   if ( handle->file )
  1075   {
  1076   	if ( seekFile(handle, size - totalbytesread) < 0 )
  1077   	{
  1078   	   return -1;	
  1079   	}
  1080   	else
  1081   	{
  1082   	   return size;	
  1083   	}
  1084   }
  1085   else
  1086   {
  1087   	bytesread = discardData(handle, size - totalbytesread);
  1088 	  if (bytesread < 0)
  1089     	return -1;
  1090   	totalbytesread += bytesread;
  1091   }
  1092   return totalbytesread;
  1093 }
  1094 
  1095 
  1096 /*
  1097  * Function:
  1098  *
  1099  *   mp4_i32 readTKHD(MP4HandleImp handle,
  1100  *                    trackHeaderAtom *tkhd)
  1101  *
  1102  * Description:
  1103  *
  1104  *   This function parses one TKHD atom.
  1105  *
  1106  * Parameters:
  1107  *
  1108  *   handle             MP4 library handle
  1109  *   tkhd               TKHD pointer
  1110  *
  1111  * Return value:
  1112  *
  1113  *   Negative integer   Error
  1114  *   >= 0               Success. Value tells how many bytes were read.
  1115  *
  1116  */
  1117 mp4_i32 readTKHD(MP4HandleImp handle, trackHeaderAtom *tkhd)
  1118 {
  1119   mp4_i32 bytesread;
  1120   mp4_i32 totalbytesread = 0;
  1121 
  1122 
  1123   if ((tkhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  1124     return -100;
  1125 
  1126   bytesread = readFullAtomHeader(handle, tkhd->atomhdr);
  1127   if (bytesread < 0)
  1128     return -1;
  1129   totalbytesread += bytesread;
  1130 
  1131   if (tkhd->atomhdr->type != ATOMTYPE_TKHD)
  1132     return -1;
  1133 
  1134   if (tkhd->atomhdr->version == 1) /* 64 bit */
  1135   {
  1136     bytesread = readData(handle, handle->buf, 8);
  1137     if (bytesread < 0)
  1138       return -1;
  1139     tkhd->creationTime64 = u64endian(*((mp4_u64 *)handle->buf));
  1140     totalbytesread += bytesread;
  1141 
  1142     bytesread = readData(handle, handle->buf, 8);
  1143     if (bytesread < 0)
  1144       return -1;
  1145     tkhd->modificationTime64 = u64endian(*((mp4_u64 *)handle->buf));
  1146     totalbytesread += bytesread;
  1147 
  1148     bytesread = readData(handle, handle->buf, 4);
  1149     if (bytesread < 0)
  1150       return -1;
  1151     tkhd->trackID = u32endian(*((mp4_u32 *)handle->buf));
  1152     totalbytesread += bytesread;
  1153 
  1154     bytesread = readData(handle, handle->buf, 4);
  1155     if (bytesread < 0)
  1156       return -1;
  1157     tkhd->reserved = u32endian(*((mp4_u32 *)handle->buf));
  1158     totalbytesread += bytesread;
  1159 
  1160     bytesread = readData(handle, handle->buf, 8);
  1161     if (bytesread < 0)
  1162       return -1;
  1163     tkhd->duration64 = u64endian(*((mp4_u64 *)handle->buf));
  1164     totalbytesread += bytesread;
  1165   }
  1166   else /* 32 bit */
  1167   {
  1168     bytesread = readData(handle, handle->buf, 4);
  1169     if (bytesread < 0)
  1170       return -1;
  1171     tkhd->creationTime = u32endian(*((mp4_u32 *)handle->buf));
  1172     totalbytesread += bytesread;
  1173 
  1174     bytesread = readData(handle, handle->buf, 4);
  1175     if (bytesread < 0)
  1176       return -1;
  1177     tkhd->modificationTime = u32endian(*((mp4_u32 *)handle->buf));
  1178     totalbytesread += bytesread;
  1179 
  1180     bytesread = readData(handle, handle->buf, 4);
  1181     if (bytesread < 0)
  1182       return -1;
  1183     tkhd->trackID = u32endian(*((mp4_u32 *)handle->buf));
  1184     totalbytesread += bytesread;
  1185 
  1186     bytesread = readData(handle, handle->buf, 4);
  1187     if (bytesread < 0)
  1188       return -1;
  1189     tkhd->reserved = u32endian(*((mp4_u32 *)handle->buf));
  1190     totalbytesread += bytesread;
  1191 
  1192     bytesread = readData(handle, handle->buf, 4);
  1193     if (bytesread < 0)
  1194       return -1;
  1195     tkhd->duration = u32endian(*((mp4_u32 *)handle->buf));
  1196     totalbytesread += bytesread;
  1197   }
  1198 
  1199   bytesread = discardData(handle, 52);
  1200   if (bytesread < 0)
  1201     return -1;
  1202   totalbytesread += bytesread;
  1203 
  1204   bytesread = readData(handle, handle->buf, 4);
  1205   if (bytesread < 0)
  1206     return -1;
  1207   tkhd->width = u16endian(*((mp4_u16 *)handle->buf));
  1208   totalbytesread += bytesread;
  1209 
  1210   bytesread = readData(handle, handle->buf, 4);
  1211   if (bytesread < 0)
  1212     return -1;
  1213   tkhd->height = u16endian(*((mp4_u16 *)handle->buf));
  1214   totalbytesread += bytesread;
  1215 
  1216   return totalbytesread;
  1217 }
  1218 
  1219 
  1220 /*
  1221  * Function:
  1222  *
  1223  *   mp4_i32 readTREF(MP4HandleImp handle,
  1224  *                    trackReferenceAtom *tref)
  1225  *
  1226  * Description:
  1227  *
  1228  *   This function parses one TREF atom and discards the contents.
  1229  *
  1230  * Parameters:
  1231  *
  1232  *   handle             MP4 library handle
  1233  *   tref               TREF pointer
  1234  *
  1235  * Return value:
  1236  *
  1237  *   Negative integer   Error
  1238  *   >= 0               Success. Value tells how many bytes were read.
  1239  *
  1240  */
  1241 mp4_i32 readTREF(MP4HandleImp handle, trackReferenceAtom *tref)
  1242 {
  1243   mp4_i32 bytesread;
  1244   mp4_i32 totalbytesread = 0;
  1245 
  1246 
  1247   if ((tref->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  1248     return -100;
  1249 
  1250   bytesread = readAtomHeader(handle, tref->atomhdr);
  1251   if (bytesread < 0)
  1252     return -1;
  1253   totalbytesread += bytesread;
  1254 
  1255   if (tref->atomhdr->type != ATOMTYPE_TREF)
  1256     return -1;
  1257 
  1258   bytesread = discardData(handle, tref->atomhdr->size - totalbytesread);
  1259   if (bytesread < 0)
  1260     return -1;
  1261   totalbytesread += bytesread;
  1262 
  1263   return totalbytesread;
  1264 }
  1265 
  1266 
  1267 /*
  1268  * Function:
  1269  *
  1270  *   mp4_i32 readEDTS(MP4HandleImp handle,
  1271  *                    editListContainerAtom *edts)
  1272  *
  1273  * Description:
  1274  *
  1275  *   This function parses one EDTS atom and discards the contents.
  1276  *
  1277  * Parameters:
  1278  *
  1279  *   handle             MP4 library handle
  1280  *   edts               EDTS pointer
  1281  *
  1282  * Return value:
  1283  *
  1284  *   Negative integer   Error
  1285  *   >= 0               Success. Value tells how many bytes were read.
  1286  *
  1287  */
  1288 mp4_i32 readEDTS(MP4HandleImp handle, editListContainerAtom *edts)
  1289 {
  1290   mp4_i32 bytesread;
  1291   mp4_i32 totalbytesread = 0;
  1292 
  1293 
  1294   if ((edts->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  1295     return -100;
  1296 
  1297   bytesread = readAtomHeader(handle, edts->atomhdr);
  1298   if (bytesread < 0)
  1299     return -1;
  1300   totalbytesread += bytesread;
  1301 
  1302   if (edts->atomhdr->type != ATOMTYPE_EDTS)
  1303     return -1;
  1304 
  1305   bytesread = discardData(handle, edts->atomhdr->size - totalbytesread);
  1306   if (bytesread < 0)
  1307     return -1;
  1308   totalbytesread += bytesread;
  1309 
  1310   return totalbytesread;
  1311 }
  1312 
  1313 
  1314 /*
  1315  * Function:
  1316  *
  1317  *   mp4_i32 readMDIA(MP4HandleImp handle,
  1318  *                    mediaAtom *mdia)
  1319  *
  1320  * Description:
  1321  *
  1322  *   This function parses one MDIA atom.
  1323  *
  1324  * Parameters:
  1325  *
  1326  *   handle             MP4 library handle
  1327  *   mdia               MDIA pointer
  1328  *
  1329  * Return value:
  1330  *
  1331  *   Negative integer   Error
  1332  *   >= 0               Success. Value tells how many bytes were read.
  1333  *
  1334  */
  1335 mp4_i32 readMDIA(MP4HandleImp handle, mediaAtom *mdia)
  1336 {
  1337   mp4_i32 bytesread;
  1338   mp4_i32 totalbytesread = 0;
  1339 
  1340 
  1341   if ((mdia->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  1342     return -100;
  1343 
  1344   bytesread = readAtomHeader(handle, mdia->atomhdr);
  1345   if (bytesread < 0)
  1346     return -1;
  1347   totalbytesread += bytesread;
  1348 
  1349   if (mdia->atomhdr->type != ATOMTYPE_MDIA)
  1350     return -1;
  1351 
  1352 
  1353   while ((mp4_u32)totalbytesread < mdia->atomhdr->size)
  1354   {
  1355     mp4_u32 type;
  1356 
  1357 
  1358     if (peekData(handle, handle->buf, 8) < 0)
  1359       return -1;
  1360 
  1361     type = u32endian(*((mp4_u32 *)(handle->buf+4)));
  1362 
  1363     switch (type)
  1364     {
  1365     case ATOMTYPE_MDHD:
  1366 
  1367       if (mdia->mdhd) /* MDHD has already been read, more than one is not allowed */
  1368         return -1;
  1369 
  1370       if ((mdia->mdhd = (mediaHeaderAtom *)mp4malloc(sizeof(mediaHeaderAtom))) == NULL)
  1371         return -100;
  1372 
  1373       bytesread = readMDHD(handle, mdia->mdhd);
  1374       if (bytesread < 0)
  1375         return -1;
  1376       totalbytesread += bytesread;
  1377 
  1378       break;
  1379 
  1380     case ATOMTYPE_HDLR:
  1381 
  1382       if (mdia->hdlr) /* HDLR has already been read, more than one is not allowed */
  1383         return -1;
  1384 
  1385       if ((mdia->hdlr = (handlerAtom *)mp4malloc(sizeof(handlerAtom))) == NULL)
  1386         return -100;
  1387 
  1388       bytesread = readHDLR(handle, mdia->hdlr);
  1389       if (bytesread < 0)
  1390         return -1;
  1391       totalbytesread += bytesread;
  1392 
  1393       break;
  1394 
  1395     case ATOMTYPE_MINF:
  1396 
  1397       if (mdia->minf) /* MINF has already been read, more than one is not allowed */
  1398         return -1;
  1399 
  1400       if ((mdia->minf = (mediaInformationAtom *)mp4malloc(sizeof(mediaInformationAtom))) == NULL)
  1401         return -100;
  1402 
  1403       bytesread = readMINF(handle, mdia->minf);
  1404       if (bytesread < 0)
  1405         return -1;
  1406       totalbytesread += bytesread;
  1407 
  1408       break;
  1409 
  1410     default:
  1411 
  1412       bytesread = readUnknown(handle);
  1413       if (bytesread < 0)
  1414         return -1;
  1415       totalbytesread += bytesread;
  1416 
  1417       break;
  1418     }
  1419   }
  1420 
  1421   return totalbytesread;
  1422 }
  1423 
  1424 
  1425 /*
  1426  * Function:
  1427  *
  1428  *   mp4_i32 readMDHD(MP4HandleImp handle,
  1429  *                    mediaHeaderAtom *mdhd)
  1430  *
  1431  * Description:
  1432  *
  1433  *   This function parses one MDHD atom.
  1434  *
  1435  * Parameters:
  1436  *
  1437  *   handle             MP4 library handle
  1438  *   mdhd               MDHD pointer
  1439  *
  1440  * Return value:
  1441  *
  1442  *   Negative integer   Error
  1443  *   >= 0               Success. Value tells how many bytes were read.
  1444  *
  1445  */
  1446 mp4_i32 readMDHD(MP4HandleImp handle, mediaHeaderAtom *mdhd)
  1447 {
  1448   mp4_i32 bytesread;
  1449   mp4_i32 totalbytesread = 0;
  1450 
  1451 
  1452   if ((mdhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  1453     return -100;
  1454 
  1455   bytesread = readFullAtomHeader(handle, mdhd->atomhdr);
  1456   if (bytesread < 0)
  1457     return -1;
  1458   totalbytesread += bytesread;
  1459 
  1460   if (mdhd->atomhdr->type != ATOMTYPE_MDHD)
  1461     return -1;
  1462 
  1463 
  1464   if (mdhd->atomhdr->version == 1) /* 64 bit */
  1465   {
  1466     bytesread = readData(handle, handle->buf, 8);
  1467     if (bytesread < 0)
  1468       return -1;
  1469     mdhd->creationTime64 = u64endian(*((mp4_u64 *)handle->buf));
  1470     totalbytesread += bytesread;
  1471 
  1472     bytesread = readData(handle, handle->buf, 8);
  1473     if (bytesread < 0)
  1474       return -1;
  1475     mdhd->modificationTime64 = u64endian(*((mp4_u64 *)handle->buf));
  1476     totalbytesread += bytesread;
  1477 
  1478     bytesread = readData(handle, handle->buf, 4);
  1479     if (bytesread < 0)
  1480       return -1;
  1481     mdhd->timeScale = u32endian(*((mp4_u32 *)handle->buf));
  1482     totalbytesread += bytesread;
  1483 
  1484     bytesread = readData(handle, handle->buf, 8);
  1485     if (bytesread < 0)
  1486       return -1;
  1487     mdhd->duration64 = u64endian(*((mp4_u64 *)handle->buf));
  1488     totalbytesread += bytesread;
  1489   }
  1490   else /* 32 bit */
  1491   {
  1492     bytesread = readData(handle, handle->buf, 4);
  1493     if (bytesread < 0)
  1494       return -1;
  1495     mdhd->creationTime = u32endian(*((mp4_u32 *)handle->buf));
  1496     totalbytesread += bytesread;
  1497 
  1498     bytesread = readData(handle, handle->buf, 4);
  1499     if (bytesread < 0)
  1500       return -1;
  1501     mdhd->modificationTime = u32endian(*((mp4_u32 *)handle->buf));
  1502     totalbytesread += bytesread;
  1503 
  1504     bytesread = readData(handle, handle->buf, 4);
  1505     if (bytesread < 0)
  1506       return -1;
  1507     mdhd->timeScale = u32endian(*((mp4_u32 *)handle->buf));
  1508     totalbytesread += bytesread;
  1509 
  1510     bytesread = readData(handle, handle->buf, 4);
  1511     if (bytesread < 0)
  1512       return -1;
  1513     mdhd->duration = u32endian(*((mp4_u32 *)handle->buf));
  1514     totalbytesread += bytesread;
  1515   }
  1516 
  1517   bytesread = discardData(handle, 4);
  1518   if (bytesread < 0)
  1519     return -1;
  1520   totalbytesread += bytesread;
  1521 
  1522   return totalbytesread;
  1523 }
  1524 
  1525 
  1526 /*
  1527  * Function:
  1528  *
  1529  *   mp4_i32 readHDLR(MP4HandleImp handle,
  1530  *                    handlerAtom *hdlr)
  1531  *
  1532  * Description:
  1533  *
  1534  *   This function parses one HDLR atom.
  1535  *
  1536  * Parameters:
  1537  *
  1538  *   handle             MP4 library handle
  1539  *   hdlr               HDLR pointer
  1540  *
  1541  * Return value:
  1542  *
  1543  *   Negative integer   Error
  1544  *   >= 0               Success. Value tells how many bytes were read.
  1545  *
  1546  */
  1547 mp4_i32 readHDLR(MP4HandleImp handle, handlerAtom *hdlr)
  1548 {
  1549   mp4_i32 bytesread;
  1550   mp4_i32 totalbytesread = 0;
  1551 
  1552 
  1553   if ((hdlr->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  1554     return -100;
  1555 
  1556   bytesread = readFullAtomHeader(handle, hdlr->atomhdr);
  1557   if (bytesread < 0)
  1558     return -1;
  1559   totalbytesread += bytesread;
  1560 
  1561   if (hdlr->atomhdr->type != ATOMTYPE_HDLR)
  1562     return -1;
  1563 
  1564 
  1565   bytesread = discardData(handle, 4);
  1566   if (bytesread < 0)
  1567     return -1;
  1568   totalbytesread += bytesread;
  1569 
  1570   bytesread = readData(handle, handle->buf, 4);
  1571   if (bytesread < 0)
  1572     return -1;
  1573   hdlr->handlerType = u32endian(*((mp4_u32 *)handle->buf));
  1574   totalbytesread += bytesread;
  1575 
  1576   bytesread = discardData(handle, hdlr->atomhdr->size - totalbytesread);
  1577   if (bytesread < 0)
  1578     return -1;
  1579   totalbytesread += bytesread;
  1580 
  1581   return totalbytesread;
  1582 }
  1583 
  1584 
  1585 /*
  1586  * Function:
  1587  *
  1588  *   mp4_i32 readMINF(MP4HandleImp handle,
  1589  *                    mediaInformationAtom *minf)
  1590  *
  1591  * Description:
  1592  *
  1593  *   This function parses one MINF atom.
  1594  *
  1595  * Parameters:
  1596  *
  1597  *   handle             MP4 library handle
  1598  *   minf               MINF pointer
  1599  *
  1600  * Return value:
  1601  *
  1602  *   Negative integer   Error
  1603  *   >= 0               Success. Value tells how many bytes were read.
  1604  *
  1605  */
  1606 mp4_i32 readMINF(MP4HandleImp handle, mediaInformationAtom *minf)
  1607 {
  1608   mp4_i32 bytesread;
  1609   mp4_i32 totalbytesread = 0;
  1610 
  1611 
  1612   if ((minf->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  1613     return -100;
  1614 
  1615   bytesread = readAtomHeader(handle, minf->atomhdr);
  1616   if (bytesread < 0)
  1617     return -1;
  1618   totalbytesread += bytesread;
  1619 
  1620   if (minf->atomhdr->type != ATOMTYPE_MINF)
  1621     return -1;
  1622 
  1623 
  1624   while ((mp4_u32)totalbytesread < minf->atomhdr->size)
  1625   {
  1626     mp4_u32 type;
  1627 
  1628 
  1629     if (peekData(handle, handle->buf, 8) < 0)
  1630       return -1;
  1631 
  1632     type = u32endian(*((mp4_u32 *)(handle->buf+4)));
  1633 
  1634     switch (type)
  1635     {
  1636     case ATOMTYPE_VMHD:
  1637 
  1638       if (minf->vmhd || minf->smhd) /* VMHD or SMHD has already been read, more than one is not allowed */
  1639         return -1;
  1640 
  1641       if ((minf->vmhd = (videoMediaHeaderAtom *)mp4malloc(sizeof(videoMediaHeaderAtom))) == NULL)
  1642         return -100;
  1643 
  1644       bytesread = readVMHD(handle, minf->vmhd);
  1645       if (bytesread < 0)
  1646         return -1;
  1647       totalbytesread += bytesread;
  1648 
  1649       break;
  1650 
  1651     case ATOMTYPE_SMHD:
  1652 
  1653       if (minf->smhd || minf->vmhd) /* SMHD or VMHD has already been read, more than one is not allowed */
  1654         return -1;
  1655 
  1656       if ((minf->smhd = (soundMediaHeaderAtom *)mp4malloc(sizeof(soundMediaHeaderAtom))) == NULL)
  1657         return -100;
  1658 
  1659       bytesread = readSMHD(handle, minf->smhd);
  1660       if (bytesread < 0)
  1661         return -1;
  1662       totalbytesread += bytesread;
  1663 
  1664       break;
  1665 
  1666     case ATOMTYPE_DINF:
  1667 
  1668       if (minf->dinf) /* DINF has already been read, more than one is not allowed */
  1669         return -1;
  1670 
  1671       if ((minf->dinf = (dataInformationAtom *)mp4malloc(sizeof(dataInformationAtom))) == NULL)
  1672         return -100;
  1673 
  1674       bytesread = readDINF(handle, minf->dinf);
  1675       if (bytesread < 0)
  1676         return -1;
  1677       totalbytesread += bytesread;
  1678 
  1679       break;
  1680 
  1681     case ATOMTYPE_STBL:
  1682 
  1683       if (minf->stbl) /* STBL has already been read, more than one is not allowed */
  1684         return -1;
  1685 
  1686       if ((minf->stbl = (sampleTableAtom *)mp4malloc(sizeof(sampleTableAtom))) == NULL)
  1687         return -100;
  1688 
  1689       bytesread = readSTBL(handle, minf->stbl);
  1690       if (bytesread < 0)
  1691         return -1;
  1692       totalbytesread += bytesread;
  1693 
  1694       break;
  1695 
  1696     default:
  1697 
  1698       bytesread = readUnknown(handle);
  1699       if (bytesread < 0)
  1700         return -1;
  1701       totalbytesread += bytesread;
  1702 
  1703       break;
  1704     }
  1705   }
  1706 
  1707   return totalbytesread;
  1708 }
  1709 
  1710 
  1711 /*
  1712  * Function:
  1713  *
  1714  *   mp4_i32 readVMHD(MP4HandleImp handle,
  1715  *                    videoMediaHeaderAtom *vmhd)
  1716  *
  1717  * Description:
  1718  *
  1719  *   This function parses one VMHD atom.
  1720  *
  1721  * Parameters:
  1722  *
  1723  *   handle             MP4 library handle
  1724  *   vmhd               VMHD pointer
  1725  *
  1726  * Return value:
  1727  *
  1728  *   Negative integer   Error
  1729  *   >= 0               Success. Value tells how many bytes were read.
  1730  *
  1731  */
  1732 mp4_i32 readVMHD(MP4HandleImp handle, videoMediaHeaderAtom *vmhd)
  1733 {
  1734   mp4_i32 bytesread;
  1735   mp4_i32 totalbytesread = 0;
  1736 
  1737 
  1738   if ((vmhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  1739     return -100;
  1740 
  1741   bytesread = readFullAtomHeader(handle, vmhd->atomhdr);
  1742   if (bytesread < 0)
  1743     return -1;
  1744   totalbytesread += bytesread;
  1745 
  1746   if (vmhd->atomhdr->type != ATOMTYPE_VMHD)
  1747     return -1;
  1748 
  1749 
  1750   bytesread = discardData(handle, vmhd->atomhdr->size - totalbytesread);
  1751   if (bytesread < 0)
  1752     return -1;
  1753   totalbytesread += bytesread;
  1754 
  1755   return totalbytesread;
  1756 }
  1757 
  1758 
  1759 /*
  1760  * Function:
  1761  *
  1762  *   mp4_i32 readSMHD(MP4HandleImp handle,
  1763  *                    soundMediaHeaderAtom *smhd)
  1764  *
  1765  * Description:
  1766  *
  1767  *   This function parses one SMHD atom.
  1768  *
  1769  * Parameters:
  1770  *
  1771  *   handle             MP4 library handle
  1772  *   smhd               SMHD pointer
  1773  *
  1774  * Return value:
  1775  *
  1776  *   Negative integer   Error
  1777  *   >= 0               Success. Value tells how many bytes were read.
  1778  *
  1779  */
  1780 mp4_i32 readSMHD(MP4HandleImp handle, soundMediaHeaderAtom *smhd)
  1781 {
  1782   mp4_i32 bytesread;
  1783   mp4_i32 totalbytesread = 0;
  1784 
  1785 
  1786   if ((smhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  1787     return -100;
  1788 
  1789   bytesread = readFullAtomHeader(handle, smhd->atomhdr);
  1790   if (bytesread < 0)
  1791     return -1;
  1792   totalbytesread += bytesread;
  1793 
  1794   if (smhd->atomhdr->type != ATOMTYPE_SMHD)
  1795     return -1;
  1796 
  1797 
  1798   bytesread = discardData(handle, smhd->atomhdr->size - totalbytesread);
  1799   if (bytesread < 0)
  1800     return -1;
  1801   totalbytesread += bytesread;
  1802 
  1803   return totalbytesread;
  1804 }
  1805 
  1806 
  1807 /*
  1808  * Function:
  1809  *
  1810  *   mp4_i32 readDINF(MP4HandleImp handle,
  1811  *                    dataInformationAtom *dinf)
  1812  *
  1813  * Description:
  1814  *
  1815  *   This function parses one DINF atom.
  1816  *
  1817  * Parameters:
  1818  *
  1819  *   handle             MP4 library handle
  1820  *   dinf               DINF pointer
  1821  *
  1822  * Return value:
  1823  *
  1824  *   Negative integer   Error
  1825  *   >= 0               Success. Value tells how many bytes were read.
  1826  *
  1827  */
  1828 mp4_i32 readDINF(MP4HandleImp handle, dataInformationAtom *dinf)
  1829 {
  1830   mp4_i32 bytesread;
  1831   mp4_i32 totalbytesread = 0;
  1832 
  1833 
  1834   if ((dinf->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  1835     return -100;
  1836 
  1837   bytesread = readAtomHeader(handle, dinf->atomhdr);
  1838   if (bytesread < 0)
  1839     return -1;
  1840   totalbytesread += bytesread;
  1841 
  1842   if (dinf->atomhdr->type != ATOMTYPE_DINF)
  1843     return -1;
  1844 
  1845 
  1846   while ((mp4_u32)totalbytesread < dinf->atomhdr->size)
  1847   {
  1848     mp4_u32 type;
  1849 
  1850 
  1851     if (peekData(handle, handle->buf, 8) < 0)
  1852       return -1;
  1853 
  1854     type = u32endian(*((mp4_u32 *)(handle->buf+4)));
  1855 
  1856     switch (type)
  1857     {
  1858     case ATOMTYPE_DREF:
  1859 
  1860       if (dinf->dref) /* DINF has already been read, more than one is not allowed */
  1861         return -1;
  1862 
  1863       if ((dinf->dref = (dataReferenceAtom *)mp4malloc(sizeof(dataReferenceAtom))) == NULL)
  1864         return -100;
  1865 
  1866       bytesread = readDREF(handle, dinf->dref);
  1867       if (bytesread < 0)
  1868         return -1;
  1869       totalbytesread += bytesread;
  1870 
  1871       break;
  1872 
  1873     default:
  1874 
  1875       return -1;
  1876     }
  1877   }
  1878 
  1879   return totalbytesread;
  1880 }
  1881 
  1882 
  1883 /*
  1884  * Function:
  1885  *
  1886  *   mp4_i32 readDREF(MP4HandleImp handle,
  1887  *                    dataReferenceAtom *dref)
  1888  *
  1889  * Description:
  1890  *
  1891  *   This function parses one DREF atom.
  1892  *
  1893  * Parameters:
  1894  *
  1895  *   handle             MP4 library handle
  1896  *   dref               DREF pointer
  1897  *
  1898  * Return value:
  1899  *
  1900  *   Negative integer   Error
  1901  *   >= 0               Success. Value tells how many bytes were read.
  1902  *
  1903  */
  1904 mp4_i32 readDREF(MP4HandleImp handle, dataReferenceAtom *dref)
  1905 {
  1906   mp4_i32 bytesread;
  1907   mp4_i32 totalbytesread = 0;
  1908 
  1909 
  1910   if ((dref->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  1911     return -100;
  1912 
  1913   bytesread = readFullAtomHeader(handle, dref->atomhdr);
  1914   if (bytesread < 0)
  1915     return -1;
  1916   totalbytesread += bytesread;
  1917 
  1918   if (dref->atomhdr->type != ATOMTYPE_DREF)
  1919     return -1;
  1920 
  1921 
  1922   bytesread = readData(handle, handle->buf, 4);
  1923   if (bytesread < 0)
  1924     return -1;
  1925   dref->entryCount = u32endian(*((mp4_u32 *)handle->buf));
  1926   totalbytesread += bytesread;
  1927 
  1928   if (dref->entryCount != 1)
  1929     return -1;
  1930 
  1931   while ((mp4_u32)totalbytesread < dref->atomhdr->size)
  1932   {
  1933     bytesread = readUnknown(handle);
  1934     if (bytesread < 0)
  1935       return -1;
  1936     totalbytesread += bytesread;
  1937   }
  1938   return totalbytesread;
  1939 }
  1940 
  1941 
  1942 /*
  1943  * Function:
  1944  *
  1945  *   mp4_i32 readURL(MP4HandleImp handle,
  1946  *                   dataEntryURLAtom *url)
  1947  *
  1948  * Description:
  1949  *
  1950  *   This function parses one URL atom.
  1951  *
  1952  * Parameters:
  1953  *
  1954  *   handle             MP4 library handle
  1955  *   url                URL pointer
  1956  *
  1957  * Return value:
  1958  *
  1959  *   Negative integer   Error
  1960  *   >= 0               Success. Value tells how many bytes were read.
  1961  *
  1962  */
  1963 mp4_i32 readURL(MP4HandleImp handle, dataEntryURLAtom *url)
  1964 {
  1965   mp4_i32 bytesread;
  1966   mp4_i32 totalbytesread = 0;
  1967 
  1968 
  1969   if ((url->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  1970     return -100;
  1971 
  1972   bytesread = readFullAtomHeader(handle, url->atomhdr);
  1973   if (bytesread < 0)
  1974     return -1;
  1975   totalbytesread += bytesread;
  1976 
  1977   if (url->atomhdr->type != ATOMTYPE_URL)
  1978     return -1;
  1979 
  1980 
  1981   if (!(url->atomhdr->flags[0] == 0x00 &&
  1982         url->atomhdr->flags[1] == 0x00 &&
  1983         url->atomhdr->flags[2] == 0x01))
  1984     return -1;
  1985 
  1986   return totalbytesread;
  1987 }
  1988 
  1989 
  1990 /*
  1991  * Function:
  1992  *
  1993  *   mp4_i32 readURN(MP4HandleImp handle,
  1994  *                   dataEntryURNAtom *urn)
  1995  *
  1996  * Description:
  1997  *
  1998  *   This function parses one URN atom.
  1999  *
  2000  * Parameters:
  2001  *
  2002  *   handle             MP4 library handle
  2003  *   urn                URN pointer
  2004  *
  2005  * Return value:
  2006  *
  2007  *   Negative integer   Error
  2008  *   >= 0               Success. Value tells how many bytes were read.
  2009  *
  2010  */
  2011 mp4_i32 readURN(MP4HandleImp handle, dataEntryURNAtom *urn)
  2012 {
  2013   mp4_i32 bytesread;
  2014   mp4_i32 totalbytesread = 0;
  2015 
  2016 
  2017   if ((urn->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  2018     return -100;
  2019 
  2020   bytesread = readFullAtomHeader(handle, urn->atomhdr);
  2021   if (bytesread < 0)
  2022     return -1;
  2023   totalbytesread += bytesread;
  2024 
  2025   if (urn->atomhdr->type != ATOMTYPE_URN)
  2026     return -1;
  2027 
  2028 
  2029   if (!(urn->atomhdr->flags[0] == 0x00 &&
  2030         urn->atomhdr->flags[1] == 0x00 &&
  2031         urn->atomhdr->flags[2] == 0x01))
  2032     return -1;
  2033 
  2034   return totalbytesread;
  2035 }
  2036 
  2037 
  2038 /*
  2039  * Function:
  2040  *
  2041  *   mp4_i32 readSTBL(MP4HandleImp handle,
  2042  *                    sampleTableAtom *stbl)
  2043  *
  2044  * Description:
  2045  *
  2046  *   This function parses one STBL atom.
  2047  *
  2048  * Parameters:
  2049  *
  2050  *   handle             MP4 library handle
  2051  *   stbl               STBL pointer
  2052  *
  2053  * Return value:
  2054  *
  2055  *   Negative integer   Error
  2056  *   >= 0               Success. Value tells how many bytes were read.
  2057  *
  2058  */
  2059 mp4_i32 readSTBL(MP4HandleImp handle, sampleTableAtom *stbl)
  2060 {
  2061   mp4_i32 bytesread;
  2062   mp4_i32 totalbytesread = 0;
  2063 
  2064 
  2065   if ((stbl->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  2066     return -100;
  2067 
  2068   bytesread = readAtomHeader(handle, stbl->atomhdr);
  2069   if (bytesread < 0)
  2070     return -1;
  2071   totalbytesread += bytesread;
  2072 
  2073   if (stbl->atomhdr->type != ATOMTYPE_STBL)
  2074     return -1;
  2075 
  2076 
  2077   while ((mp4_u32)totalbytesread < stbl->atomhdr->size)
  2078   {
  2079     mp4_u32 type;
  2080 
  2081 
  2082     if (peekData(handle, handle->buf, 8) < 0)
  2083       return -1;
  2084 
  2085     type = u32endian(*((mp4_u32 *)(handle->buf+4)));
  2086 
  2087     switch (type)
  2088     {
  2089     case ATOMTYPE_STTS:
  2090 
  2091       if (stbl->stts) /* STTS has already been read, more than one is not allowed */
  2092         return -1;
  2093 
  2094       if ((stbl->stts = (timeToSampleAtom *)mp4malloc(sizeof(timeToSampleAtom))) == NULL)
  2095         return -100;
  2096 
  2097       bytesread = readSTTS(handle, stbl->stts);
  2098       if (bytesread < 0)
  2099         return -1;
  2100       totalbytesread += bytesread;
  2101 
  2102       break;
  2103 
  2104     case ATOMTYPE_CTTS:
  2105 
  2106       if (stbl->ctts) /* CTTS has already been read, more than one is not allowed */
  2107         return -1;
  2108 
  2109       if ((stbl->ctts = (compositionTimeToSampleAtom *)mp4malloc(sizeof(compositionTimeToSampleAtom))) == NULL)
  2110         return -100;
  2111 
  2112       bytesread = readCTTS(handle, stbl->ctts);
  2113       if (bytesread < 0)
  2114         return -1;
  2115       totalbytesread += bytesread;
  2116 
  2117       break;
  2118 
  2119     case ATOMTYPE_STSS:
  2120 
  2121       if (stbl->stss) /* STSS has already been read, more than one is not allowed */
  2122         return -1;
  2123 
  2124       if ((stbl->stss = (syncSampleAtom *)mp4malloc(sizeof(syncSampleAtom))) == NULL)
  2125         return -100;
  2126 
  2127       bytesread = readSTSS(handle, stbl->stss);
  2128       if (bytesread < 0)
  2129         return -1;
  2130       totalbytesread += bytesread;
  2131 
  2132       break;
  2133 
  2134     case ATOMTYPE_STSD:
  2135 
  2136       if (stbl->stsd) /* STSD has already been read, more than one is not allowed */
  2137         return -1;
  2138 
  2139       if ((stbl->stsd = (sampleDescriptionAtom *)mp4malloc(sizeof(sampleDescriptionAtom))) == NULL)
  2140         return -100;
  2141 
  2142       bytesread = readSTSD(handle, stbl->stsd);
  2143       if (bytesread < 0)
  2144         return -1;
  2145       totalbytesread += bytesread;
  2146 
  2147       break;
  2148 
  2149     case ATOMTYPE_STSZ:
  2150 
  2151       if (stbl->stsz) /* STSZ or STZ2 has already been read, more than one is not allowed */
  2152         return -1;
  2153 
  2154       if ((stbl->stsz = (sampleSizeAtom *)mp4malloc(sizeof(sampleSizeAtom))) == NULL)
  2155         return -100;
  2156 
  2157       bytesread = readSTSZ(handle, stbl->stsz);
  2158       if (bytesread < 0)
  2159         return -1;
  2160       totalbytesread += bytesread;
  2161 
  2162       break;
  2163 
  2164     case ATOMTYPE_STZ2:
  2165 
  2166       if (stbl->stsz) /* STSZ or STZ2 has already been read, more than one is not allowed */
  2167         return -1;
  2168 
  2169       if ((stbl->stsz = (sampleSizeAtom *)mp4malloc(sizeof(sampleSizeAtom))) == NULL)
  2170         return -100;
  2171 
  2172       bytesread = readSTZ2(handle, stbl->stsz);
  2173       if (bytesread < 0)
  2174         return -1;
  2175       totalbytesread += bytesread;
  2176 
  2177       break;
  2178 
  2179     case ATOMTYPE_STSC:
  2180 
  2181       if (stbl->stsc) /* STSC has already been read, more than one is not allowed */
  2182         return -1;
  2183 
  2184       if ((stbl->stsc = (sampleToChunkAtom *)mp4malloc(sizeof(sampleToChunkAtom))) == NULL)
  2185         return -100;
  2186 
  2187       bytesread = readSTSC(handle, stbl->stsc);
  2188       if (bytesread < 0)
  2189         return -1;
  2190       totalbytesread += bytesread;
  2191 
  2192       break;
  2193 
  2194     case ATOMTYPE_STCO:
  2195 
  2196       if (stbl->stco) /* STCO or CO64 has already been read, more than one is not allowed */
  2197         return -1;
  2198 
  2199       if ((stbl->stco = (chunkOffsetAtom *)mp4malloc(sizeof(chunkOffsetAtom))) == NULL)
  2200         return -100;
  2201       
  2202       stbl->is32BitOffsets = ETrue;
  2203       bytesread = readSTCO(handle, stbl->stco);
  2204       if (bytesread < 0)
  2205         return -1;
  2206       totalbytesread += bytesread;
  2207 
  2208       break;
  2209 
  2210     case ATOMTYPE_CO64:
  2211 
  2212       if (stbl->stco64) /* STCO or CO64 has already been read, more than one is not allowed */
  2213         return -1;
  2214 
  2215       if ((stbl->stco64 = (chunkOffset64Atom *)mp4malloc(sizeof(chunkOffset64Atom))) == NULL)
  2216         return -100;
  2217       
  2218       stbl->is32BitOffsets = EFalse;
  2219       bytesread = readCO64(handle, stbl->stco64);
  2220       if (bytesread < 0)
  2221         return -1;
  2222       totalbytesread += bytesread;
  2223 
  2224       break;
  2225 
  2226     case ATOMTYPE_SDTP:
  2227       if (stbl->sdtp) /* SDTP has already been read, more than one is not allowed */
  2228         return -1;
  2229       
  2230       if ((stbl->sdtp = (sampleDependencyAtom *)mp4malloc(sizeof(sampleDependencyAtom))) == NULL)
  2231         return -100;
  2232 
  2233       if (!stbl->stsz)
  2234     	  {
  2235     	  return -1;
  2236     	  }
  2237 
  2238 	  // sample_count of SDTP is taken from the sample_count in the Sample Size Box ('stsz') or
  2239 	  // Compact Sample Size Box (‘stz2’). 
  2240 	  bytesread = readSDTP(handle, stbl->sdtp, stbl->stsz->sampleCount);
  2241     	  
  2242       if (bytesread < 0)
  2243         return -1;
  2244       totalbytesread += bytesread;
  2245       break;
  2246 
  2247     default: /* Other atoms are not needed */
  2248 
  2249       bytesread = readUnknown(handle);
  2250       if (bytesread < 0)
  2251         return -1;
  2252       totalbytesread += bytesread;
  2253 
  2254       break;
  2255     }
  2256   }
  2257 
  2258   return totalbytesread;
  2259 }
  2260 
  2261 
  2262 /*
  2263  * Function:
  2264  *
  2265  *   mp4_i32 readSTTS(MP4HandleImp handle,
  2266  *                    timeToSampleAtom *stts)
  2267  *
  2268  * Description:
  2269  *
  2270  *   This function parses one STTS atom.
  2271  *
  2272  * Parameters:
  2273  *
  2274  *   handle             MP4 library handle
  2275  *   stts               STTS pointer
  2276  *
  2277  * Return value:
  2278  *
  2279  *   Negative integer   Error
  2280  *   >= 0               Success. Value tells how many bytes were read.
  2281  *
  2282  */
  2283 mp4_i32 readSTTS(MP4HandleImp handle, timeToSampleAtom *stts)
  2284 {
  2285   mp4_i32 bytesread;
  2286   mp4_i32 totalbytesread = 0;
  2287   mp4_u32 i;
  2288 
  2289 
  2290   if ((stts->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  2291     return -100;
  2292 
  2293   bytesread = readFullAtomHeader(handle, stts->atomhdr);
  2294   if (bytesread < 0)
  2295     return -1;
  2296   totalbytesread += bytesread;
  2297 
  2298   if (stts->atomhdr->type != ATOMTYPE_STTS)
  2299     return -1;
  2300 
  2301 
  2302   bytesread = readData(handle, handle->buf, 4);
  2303   if (bytesread < 0)
  2304     return -1;
  2305   stts->entryCount = u32endian(*((mp4_u32 *)handle->buf));
  2306   totalbytesread += bytesread;
  2307   
  2308   if ( stts->entryCount )
  2309   {
  2310 	  stts->sampleCount = (mp4_u32 *)mp4malloc(stts->entryCount * sizeof(mp4_u32));
  2311 	  if (stts->sampleCount == NULL)
  2312 	    return -1;
  2313 	  stts->sampleDelta = (mp4_i32 *)mp4malloc(stts->entryCount * sizeof(mp4_i32));
  2314 	  if (stts->sampleDelta == NULL)
  2315 	    return -1;
  2316 
  2317 	  for (i = 0; i < stts->entryCount; i++)
  2318 	  {
  2319 	    bytesread = readData(handle, handle->buf, 8);
  2320 	    if (bytesread < 0)
  2321 	      return -1;
  2322 
  2323 	    stts->sampleCount[i] = u32endian(*((mp4_u32 *)handle->buf));
  2324 	    stts->sampleDelta[i] = i32endian(*((mp4_i32 *)(handle->buf+4)));
  2325 
  2326 	    totalbytesread += bytesread;
  2327 	  }
  2328   }
  2329 
  2330   return totalbytesread;
  2331 }
  2332 
  2333 
  2334 /*
  2335  * Function:
  2336  *
  2337  *   mp4_i32 readCTTS(MP4HandleImp handle,
  2338  *                    compositionTimeToSampleAtom *ctts)
  2339  *
  2340  * Description:
  2341  *
  2342  *   This function parses one CTTS atom.
  2343  *
  2344  * Parameters:
  2345  *
  2346  *   handle             MP4 library handle
  2347  *   ctts               CTTS pointer
  2348  *
  2349  * Return value:
  2350  *
  2351  *   Negative integer   Error
  2352  *   >= 0               Success. Value tells how many bytes were read.
  2353  *
  2354  */
  2355 mp4_i32 readCTTS(MP4HandleImp handle, compositionTimeToSampleAtom *ctts)
  2356 {
  2357   mp4_i32 bytesread;
  2358   mp4_i32 totalbytesread = 0;
  2359   mp4_u32 i;
  2360 
  2361 
  2362   if ((ctts->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  2363     return -100;
  2364 
  2365   bytesread = readFullAtomHeader(handle, ctts->atomhdr);
  2366   if (bytesread < 0)
  2367     return -1;
  2368   totalbytesread += bytesread;
  2369 
  2370   if (ctts->atomhdr->type != ATOMTYPE_CTTS)
  2371     return -1;
  2372 
  2373   bytesread = readData(handle, handle->buf, 4);
  2374   if (bytesread < 0)
  2375     return -1;
  2376   ctts->entryCount = u32endian(*((mp4_u32 *)handle->buf));
  2377   totalbytesread += bytesread;
  2378 
  2379   if ( ctts->entryCount )
  2380   {
  2381 	  ctts->sampleCount = (mp4_u32 *)mp4malloc(ctts->entryCount * sizeof(mp4_u32));
  2382 	  if (ctts->sampleCount == NULL)
  2383 	    return -1;
  2384 	  ctts->sampleOffset = (mp4_u32 *)mp4malloc(ctts->entryCount * sizeof(mp4_u32));
  2385 	  if (ctts->sampleOffset == NULL)
  2386 	    return -1;
  2387 
  2388 	  for (i = 0; i < ctts->entryCount; i++)
  2389 	  {
  2390 	    bytesread = readData(handle, handle->buf, 8);
  2391 	    if (bytesread < 0)
  2392 	      return -1;
  2393 
  2394 	    ctts->sampleCount[i] = u32endian(*((mp4_u32 *)handle->buf));
  2395 	    ctts->sampleOffset[i] = u32endian(*((mp4_u32 *)(handle->buf+4)));
  2396 
  2397 	    totalbytesread += bytesread;
  2398 	  }
  2399   }
  2400   return totalbytesread;
  2401 }
  2402 
  2403 
  2404 /*
  2405  * Function:
  2406  *
  2407  *   mp4_i32 readSTSS(MP4HandleImp handle,
  2408  *                    syncSampleAtom *stss)
  2409  *
  2410  * Description:
  2411  *
  2412  *   This function parses one STSS atom.
  2413  *
  2414  * Parameters:
  2415  *
  2416  *   handle             MP4 library handle
  2417  *   stss               STSS pointer
  2418  *
  2419  * Return value:
  2420  *
  2421  *   Negative integer   Error
  2422  *   >= 0               Success. Value tells how many bytes were read.
  2423  *
  2424  */
  2425 mp4_i32 readSTSS(MP4HandleImp handle, syncSampleAtom *stss)
  2426 {
  2427   mp4_i32 bytesread;
  2428   mp4_i32 totalbytesread = 0;
  2429   mp4_u32 i;
  2430 
  2431 
  2432   if ((stss->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  2433     return -100;
  2434 
  2435   bytesread = readFullAtomHeader(handle, stss->atomhdr);
  2436   if (bytesread < 0)
  2437     return -1;
  2438   totalbytesread += bytesread;
  2439 
  2440   if (stss->atomhdr->type != ATOMTYPE_STSS)
  2441     return -1;
  2442 
  2443 
  2444   bytesread = readData(handle, handle->buf, 4);
  2445   if (bytesread < 0)
  2446     return -1;
  2447   stss->entryCount = u32endian(*((mp4_u32 *)handle->buf));
  2448   totalbytesread += bytesread;
  2449 
  2450   if ( stss->entryCount )
  2451   {
  2452 	  stss->sampleNumber = (mp4_u32 *)mp4malloc(stss->entryCount * sizeof(mp4_u32));
  2453 	  if (stss->sampleNumber == NULL)
  2454 	    return -1;
  2455 
  2456 	  for (i = 0; i < stss->entryCount; i++)
  2457 	  {
  2458 	    bytesread = readData(handle, handle->buf, 4);
  2459 	    if (bytesread < 0)
  2460 	      return -1;
  2461 
  2462 	    stss->sampleNumber[i] = u32endian(*((mp4_u32 *)handle->buf));
  2463 
  2464 	    totalbytesread += bytesread;
  2465 	  }
  2466   }
  2467 
  2468   return totalbytesread;
  2469 }
  2470 
  2471 
  2472 /*
  2473  * Function:
  2474  *
  2475  *   mp4_i32 readSTSD(MP4HandleImp handle,
  2476  *                    sampleDescriptionAtom *stsd)
  2477  *
  2478  * Description:
  2479  *
  2480  *   This function parses one STSD atom.
  2481  *
  2482  * Parameters:
  2483  *
  2484  *   handle             MP4 library handle
  2485  *   stsd               STSD pointer
  2486  *
  2487  * Return value:
  2488  *
  2489  *   Negative integer   Error
  2490  *   >= 0               Success. Value tells how many bytes were read.
  2491  *
  2492  */
  2493 mp4_i32 readSTSD(MP4HandleImp handle, sampleDescriptionAtom *stsd)
  2494 	{
  2495 	mp4_i32 bytesread;
  2496 	mp4_i32 totalbytesread = 0;
  2497 	mp4_u32 totalsampleentriesread = 0;
  2498 	mp4_u32 unknownsampleentriesread = 0;
  2499 	mp4_bool skipentries = 0;
  2500 
  2501 	if ((stsd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  2502         {
  2503         // for memory cleanup set entrycount to allocated num of entries.
  2504         stsd->entryCount = totalsampleentriesread;
  2505 	    return -100;
  2506         }
  2507 
  2508 	bytesread = readFullAtomHeader(handle, stsd->atomhdr);
  2509 	if (bytesread < 0)
  2510 	    {
  2511 	    // for memory cleanup set entrycount to allocated num of entries.
  2512 	    stsd->entryCount = totalsampleentriesread;
  2513 	    return -1;
  2514 	    }
  2515 	totalbytesread += bytesread;
  2516 
  2517 	if (stsd->atomhdr->type != ATOMTYPE_STSD)
  2518 	    {
  2519 	    // for memory cleanup set entrycount to allocated num of entries.
  2520 	    stsd->entryCount = totalsampleentriesread;
  2521 	    return -1;
  2522 	    }
  2523 
  2524 	bytesread = readData(handle, handle->buf, 4);
  2525 	if (bytesread < 0)
  2526 	    {
  2527 	    // for memory cleanup set entrycount to allocated num of entries.
  2528 	    stsd->entryCount = totalsampleentriesread;
  2529 	    return -1;
  2530 	    }
  2531 	stsd->entryCount = u32endian(*((mp4_u32 *)handle->buf));
  2532 	totalbytesread += bytesread;
  2533 
  2534 	mp4_u32 type;
  2535 	while ((mp4_u32)totalbytesread < stsd->atomhdr->size)
  2536 		{	
  2537 		// if the number of entries read already surpasses the number of entries specified 
  2538 		// within the STSD atom, the file is corrupted.
  2539 		if ((totalsampleentriesread + unknownsampleentriesread) >= stsd->entryCount)
  2540 			{
  2541 			// for memory cleanup set entrycount to allocated num of entries.
  2542 			stsd->entryCount = totalsampleentriesread;
  2543   	  		return -1;    	    	
  2544 			}
  2545 
  2546 		// read the next sample type
  2547 		if (peekData(handle, handle->buf, 8) < 0)
  2548 	        {
  2549 	        // for memory cleanup set entrycount to allocated num of entries.
  2550 	        stsd->entryCount = totalsampleentriesread;
  2551 		    return -1;
  2552 	        }
  2553 		type = u32endian(*((mp4_u32 *)(handle->buf+4)));
  2554     
  2555 		// if the max sample entiries supported by the library has been reached 
  2556 		if ((stsd->entryCount > STSDMAXSAMPLEENTRYCOUNT) && (totalsampleentriesread == STSDMAXSAMPLEENTRYCOUNT))
  2557 			{
  2558 			// skip reading the rest of the entries to make sure no more than max count of sample entries 
  2559 			// will be processed, so that cleanup will always work. 
  2560 			type = 0;
  2561 			skipentries = 1;
  2562 			}
  2563 
  2564 		switch (type)
  2565 			{
  2566 			case ATOMTYPE_MP4V:
  2567 				{
  2568 				if (stsd->mp4v[totalsampleentriesread]) /* MP4V[totalsampleentriesread] has already been read, more than one is not allowed */ 
  2569 			        {
  2570 			        // for memory cleanup set entrycount to allocated num of entries.
  2571 			        stsd->entryCount = totalsampleentriesread;
  2572 				    return -1;
  2573 			        }
  2574 		
  2575 				if ((stsd->mp4v[totalsampleentriesread] = (visualSampleEntry *)mp4malloc(sizeof(visualSampleEntry))) == NULL)
  2576 			        {
  2577 			        // for memory cleanup set entrycount to allocated num of entries.
  2578 			        stsd->entryCount = totalsampleentriesread;
  2579 				    return -100;
  2580 			        }
  2581 		
  2582 				bytesread = readMP4V(handle, stsd->mp4v[totalsampleentriesread]);
  2583 				totalsampleentriesread++;
  2584 				if (bytesread < 0)
  2585 			        {
  2586 			        // for memory cleanup set entrycount to allocated num of entries.
  2587 			        stsd->entryCount = totalsampleentriesread;
  2588 				    return -1;
  2589 			        }
  2590 				totalbytesread += bytesread;
  2591 				break;
  2592 				}
  2593 
  2594 			case ATOMTYPE_MP4A:
  2595 				{	
  2596 				if (stsd->mp4a[totalsampleentriesread]) /* MP4A[totalsampleentriesread] has already been read, more than one is not allowed */
  2597 			        {
  2598 			        // for memory cleanup set entrycount to allocated num of entries.
  2599 			        stsd->entryCount = totalsampleentriesread;
  2600 				    return -1;
  2601 			        }
  2602 
  2603 				if ((stsd->mp4a[totalsampleentriesread] = (audioSampleEntry *)mp4malloc(sizeof(audioSampleEntry))) == NULL)
  2604 			        {
  2605 			        // for memory cleanup set entrycount to allocated num of entries.
  2606 			        stsd->entryCount = totalsampleentriesread;
  2607 				    return -100;
  2608 			        }
  2609 
  2610 				bytesread = readMP4A(handle, stsd->mp4a[totalsampleentriesread]);
  2611 				totalsampleentriesread++;
  2612 				if (bytesread < 0)
  2613 			        {
  2614 			        // for memory cleanup set entrycount to allocated num of entries.
  2615 			        stsd->entryCount = totalsampleentriesread;
  2616 				    return -1;
  2617 			        }
  2618 				totalbytesread += bytesread;
  2619 				break;
  2620 				}
  2621 
  2622 			case ATOMTYPE_MP4S:
  2623 				{
  2624 				if (stsd->mp4s[totalsampleentriesread]) /* MP4S has already been read, more than one is not allowed */
  2625 			        {
  2626 			        // for memory cleanup set entrycount to allocated num of entries.
  2627 			        stsd->entryCount = totalsampleentriesread;
  2628 				    return -1;
  2629 			        }
  2630 
  2631 				if ((stsd->mp4s[totalsampleentriesread] = (mpegSampleEntry *)mp4malloc(sizeof(mpegSampleEntry))) == NULL)
  2632 			        {
  2633 			        // for memory cleanup set entrycount to allocated num of entries.
  2634 			        stsd->entryCount = totalsampleentriesread;
  2635 				    return -100;
  2636 			        }
  2637 
  2638 				bytesread = readMP4S(handle, stsd->mp4s[totalsampleentriesread]);
  2639 				totalsampleentriesread++;
  2640 				if (bytesread < 0)
  2641 			        {
  2642 			        // for memory cleanup set entrycount to allocated num of entries.
  2643 			        stsd->entryCount = totalsampleentriesread;
  2644 				    return -1;
  2645 			        }
  2646 				totalbytesread += bytesread;
  2647 				}
  2648 				break;
  2649 
  2650 			case ATOMTYPE_S263:
  2651 				{
  2652 				if (stsd->s263[totalsampleentriesread]) /* MP4S has already been read, more than one is not allowed */
  2653 			        {
  2654 			        // for memory cleanup set entrycount to allocated num of entries.
  2655 			        stsd->entryCount = totalsampleentriesread;
  2656 				    return -1;
  2657 			        }
  2658 
  2659 				if ((stsd->s263[totalsampleentriesread] = (h263SampleEntry *)mp4malloc(sizeof(h263SampleEntry))) == NULL)
  2660 			        {
  2661 			        // for memory cleanup set entrycount to allocated num of entries.
  2662 			        stsd->entryCount = totalsampleentriesread;
  2663 				    return -100;
  2664 			        }
  2665 
  2666 				bytesread = readS263(handle, stsd->s263[totalsampleentriesread]);
  2667 				totalsampleentriesread++;
  2668 				if (bytesread < 0)
  2669 			        {
  2670 			        // for memory cleanup set entrycount to allocated num of entries.
  2671 			        stsd->entryCount = totalsampleentriesread;
  2672 				    return -1;
  2673 			        }
  2674 				totalbytesread += bytesread;
  2675 				}
  2676 				break;
  2677 
  2678 			case ATOMTYPE_SAMR:
  2679 				{
  2680 				if (stsd->samr[totalsampleentriesread]) /* SAMR has already been read, more than one is not allowed */
  2681 			        {
  2682 			        // for memory cleanup set entrycount to allocated num of entries.
  2683 			        stsd->entryCount = totalsampleentriesread;
  2684 				    return -1;
  2685 			        }
  2686 
  2687 				if ((stsd->samr[totalsampleentriesread] = (amrSampleEntry *)mp4malloc(sizeof(amrSampleEntry))) == NULL)
  2688 			        {
  2689 			        // for memory cleanup set entrycount to allocated num of entries.
  2690 			        stsd->entryCount = totalsampleentriesread;
  2691 				    return -100;
  2692 			        }
  2693 
  2694 				bytesread = readSAMR(handle, stsd->samr[totalsampleentriesread]);
  2695 				totalsampleentriesread++;
  2696 				if (bytesread < 0)
  2697 			        {
  2698 			        // for memory cleanup set entrycount to allocated num of entries.
  2699 			        stsd->entryCount = totalsampleentriesread;
  2700 				    return -1;
  2701 			        }
  2702 				totalbytesread += bytesread;
  2703 				}
  2704 				break;
  2705 
  2706 			case ATOMTYPE_SAWB:
  2707 				{
  2708 				if (stsd->sawb[totalsampleentriesread]) /* SAWB has already been read, more than one is not allowed */
  2709 			        {
  2710 			        // for memory cleanup set entrycount to allocated num of entries.
  2711 			        stsd->entryCount = totalsampleentriesread;
  2712 				    return -1;
  2713 			        }
  2714 
  2715 				if ((stsd->sawb[totalsampleentriesread] = (amrSampleEntry *)mp4malloc(sizeof(amrSampleEntry))) == NULL)
  2716 			        {
  2717 			        // for memory cleanup set entrycount to allocated num of entries.
  2718 			        stsd->entryCount = totalsampleentriesread;
  2719 				    return -100;
  2720 			        }
  2721 
  2722 				bytesread = readSAWB(handle, stsd->sawb[totalsampleentriesread]);
  2723 				totalsampleentriesread++;
  2724 				if (bytesread < 0)
  2725 			        {
  2726 			        // for memory cleanup set entrycount to allocated num of entries.
  2727 			        stsd->entryCount = totalsampleentriesread;
  2728 				    return -1;
  2729 			        }
  2730 				totalbytesread += bytesread;
  2731 				}
  2732 				break;
  2733 
  2734 			case ATOMTYPE_AVC1:
  2735 				{
  2736 				if (stsd->avc1[totalsampleentriesread]) /* AVC1 has already been read, more than one is not allowed */
  2737 					{
  2738 			        // for memory cleanup set entrycount to allocated num of entries.
  2739 			        stsd->entryCount = totalsampleentriesread;
  2740 				    return -1;
  2741 					}
  2742 				if ((stsd->avc1[totalsampleentriesread] = (avcSampleEntry *)mp4malloc(sizeof(avcSampleEntry))) == NULL)
  2743 			        {
  2744 			        // for memory cleanup set entrycount to allocated num of entries.
  2745 			        stsd->entryCount = totalsampleentriesread;
  2746 				    return -100;
  2747 			        }
  2748 
  2749 				bytesread = readAVC1(handle, stsd->avc1[totalsampleentriesread]);
  2750 				totalsampleentriesread++;
  2751 				if (bytesread < 0)
  2752 					{
  2753 			        // for memory cleanup set entrycount to allocated num of entries.
  2754 			        stsd->entryCount = totalsampleentriesread;
  2755 				    return -1;
  2756 			        }
  2757 				totalbytesread += bytesread;
  2758 				}
  2759 				break;
  2760 
  2761 			case ATOMTYPE_SQCP:
  2762 				{
  2763 				if (stsd->sqcp[totalsampleentriesread]) /* SQCP has already been read, more than one is not allowed */
  2764 			        {
  2765 			        // for memory cleanup set entrycount to allocated num of entries.
  2766 			        stsd->entryCount = totalsampleentriesread;
  2767 				    return -1;
  2768 			        }
  2769 				if ((stsd->sqcp[totalsampleentriesread] = (qcelpSampleEntry *)mp4malloc(sizeof(qcelpSampleEntry))) == NULL)
  2770 			        {
  2771 			        // for memory cleanup set entrycount to allocated num of entries.
  2772 			        stsd->entryCount = totalsampleentriesread;
  2773 				    return -100;
  2774 			        }
  2775 
  2776 				bytesread = readSQCP(handle, stsd->sqcp[totalsampleentriesread]);
  2777 				totalsampleentriesread++;
  2778 				if (bytesread < 0)
  2779 					{
  2780 			        // for memory cleanup set entrycount to allocated num of entries.
  2781 			        stsd->entryCount = totalsampleentriesread;
  2782 				    return -1;
  2783 			        }
  2784 				totalbytesread += bytesread;
  2785 				}
  2786 				break;
  2787 
  2788 			default: /* Other atoms are not needed */
  2789 				// no need to increment totalsampleentriesread as no memory is allocated for unsupported 
  2790 				// or unrecognized sample types.  Alternatively, increment the count of unknown samples.   
  2791 				// This is for ensure if a non-audio/video track can properly be parsed without being 
  2792 				// recongized as an invalid format file.
  2793 				unknownsampleentriesread++;
  2794 				bytesread = readUnknown(handle);
  2795 				if (bytesread < 0)
  2796 		    		{
  2797 		    		// for memory cleanup set entrycount to allocated num of entries.
  2798 		    		stsd->entryCount = totalsampleentriesread;
  2799 		    		return -1;
  2800 		    		}
  2801 				totalbytesread += bytesread;
  2802 				break;
  2803 			}
  2804 		}
  2805 
  2806 	// if the STSD atom's entry count is NOT the same as the number (supported & unsupported) entries parsed,
  2807 	// the atom is likely a corrupted one. 
  2808 	if ((totalsampleentriesread + unknownsampleentriesread) != stsd->entryCount)
  2809 		{
  2810 		// for memory cleanup set entrycount to allocated num of entries.
  2811 		stsd->entryCount = totalsampleentriesread;
  2812 		return -1;
  2813 		}
  2814 	else 
  2815 		{
  2816 		// if the STSD atom's entry count is the same as the number of (supported & unsupported) entries 
  2817 		// parsed, check if some entries are skipped because the max sample entry count has been reached  
  2818 		if (skipentries) 
  2819 			{
  2820 			// if STSDMAXSAMPLEENTRYCOUNT was reached edit entrycount to make sure cleanup works.
  2821 			stsd->entryCount = STSDMAXSAMPLEENTRYCOUNT;
  2822 			}
  2823 		else if (unknownsampleentriesread > 0)
  2824 			{
  2825 			// unknown (unsupported) sample entries present, set the STSD entry count to the actual 
  2826 			// number of supported sample entries detected
  2827 			stsd->entryCount = totalsampleentriesread;
  2828 			}
  2829 		}
  2830   
  2831 	return totalbytesread;
  2832 	}
  2833 
  2834 
  2835 /*
  2836  * Function:
  2837  *
  2838  *   mp4_i32 readSTSZ(MP4HandleImp handle,
  2839  *                    sampleSizeAtom *stsz)
  2840  *
  2841  * Description:
  2842  *
  2843  *   This function parses one STSZ atom.
  2844  *
  2845  * Parameters:
  2846  *
  2847  *   handle             MP4 library handle
  2848  *   stsz               STSZ pointer
  2849  *
  2850  * Return value:
  2851  *
  2852  *   Negative integer   Error
  2853  *   >= 0               Success. Value tells how many bytes were read.
  2854  *
  2855  */
  2856 mp4_i32 readSTSZ(MP4HandleImp handle, sampleSizeAtom *stsz)
  2857 {
  2858   mp4_i32 bytesread;
  2859   mp4_i32 totalbytesread = 0;
  2860 
  2861 
  2862   if ((stsz->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  2863     return -100;
  2864 
  2865   bytesread = readFullAtomHeader(handle, stsz->atomhdr);
  2866   if (bytesread < 0)
  2867     return -1;
  2868   totalbytesread += bytesread;
  2869 
  2870   if (stsz->atomhdr->type != ATOMTYPE_STSZ)
  2871     return -1;
  2872 
  2873 
  2874   bytesread = readData(handle, handle->buf, 4);
  2875   if (bytesread < 0)
  2876     return -1;
  2877   stsz->sampleSize = u32endian(*((mp4_u32 *)handle->buf));
  2878   totalbytesread += bytesread;
  2879 
  2880   bytesread = readData(handle, handle->buf, 4);
  2881   if (bytesread < 0)
  2882     return -1;
  2883   stsz->sampleCount = u32endian(*((mp4_u32 *)handle->buf));
  2884   totalbytesread += bytesread;
  2885 
  2886   // zero size samplesize means samples have different sizes, and those sizes are stored in sampleSizeEntries.
  2887   if ((stsz->sampleCount) && (stsz->sampleSize == 0))
  2888   {
  2889     mp4_u32 i;
  2890 
  2891     // check validity of stsz->sampleCount before allocating entrysize table.
  2892     if ( handle->moov->mvhd )
  2893         {
  2894         if ( handle->moov->mvhd->timeScale > 0 )
  2895             {
  2896             TUint magicNumberMaxSamplesInSec = MAXSAMPLESPERSECOND;
  2897             TUint maxSampleCount;
  2898 
  2899             if ( handle->moov->mvhd->atomhdr->version == 1 ) // 64bit duration
  2900                 {
  2901                 maxSampleCount = I64INT(handle->moov->mvhd->duration64 / TUint(handle->moov->mvhd->timeScale) + 1) * magicNumberMaxSamplesInSec;
  2902                 }
  2903             else    // 32bit duration
  2904                 {
  2905                 maxSampleCount = TUint((TUint( handle->moov->mvhd->duration  ) / TUint(handle->moov->mvhd->timeScale) + 1)) * magicNumberMaxSamplesInSec;
  2906                 }
  2907 
  2908             if ( maxSampleCount < stsz->sampleCount )
  2909                 {
  2910                 // corrupted 
  2911                 return -1;
  2912                 }
  2913             }
  2914         }
  2915 
  2916     // allocate stsz->entrySize table
  2917     stsz->entrySize = (mp4_u32 *)mp4malloc(stsz->sampleCount * sizeof(mp4_u32));
  2918     if (stsz->entrySize == NULL)
  2919       return -1;
  2920 
  2921     for (i = 0; i < stsz->sampleCount; i++)
  2922     {
  2923       bytesread = readData(handle, handle->buf, 4);
  2924       if (bytesread < 0)
  2925         return -1;
  2926 
  2927       stsz->entrySize[i] = u32endian(*((mp4_u32 *)handle->buf));
  2928 
  2929       totalbytesread += bytesread;
  2930     }
  2931   }
  2932 
  2933   return totalbytesread;
  2934 }
  2935 
  2936 
  2937 /*
  2938  * Function:
  2939  *
  2940  *   mp4_i32 readSTZ2(MP4HandleImp handle,
  2941  *                    sampleSizeAtom *stsz)
  2942  *
  2943  * Description:
  2944  *
  2945  *   This function parses one STZ2 atom.
  2946  *
  2947  *   The result is placed in STSZ structure.
  2948  *
  2949  * Parameters:
  2950  *
  2951  *   handle             MP4 library handle
  2952  *   stsz               STSZ pointer
  2953  *
  2954  * Return value:
  2955  *
  2956  *   Negative integer   Error
  2957  *   >= 0               Success. Value tells how many bytes were read.
  2958  *
  2959  */
  2960 mp4_i32 readSTZ2(MP4HandleImp handle, sampleSizeAtom *stsz)
  2961 {
  2962   mp4_i32 bytesread;
  2963   mp4_i32 totalbytesread = 0;
  2964   mp4_u8  fieldsize;
  2965 
  2966 
  2967   if ((stsz->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  2968     return -100;
  2969 
  2970   bytesread = readFullAtomHeader(handle, stsz->atomhdr);
  2971   if (bytesread < 0)
  2972     return -1;
  2973   totalbytesread += bytesread;
  2974 
  2975   if (stsz->atomhdr->type != ATOMTYPE_STZ2)
  2976     return -1;
  2977 
  2978 
  2979   bytesread = discardData(handle, 3);
  2980   if (bytesread < 0)
  2981     return -1;
  2982   totalbytesread += bytesread;
  2983 
  2984   bytesread = readData(handle, handle->buf, 1);
  2985   if (bytesread < 0)
  2986     return -1;
  2987   fieldsize = handle->buf[0];
  2988   totalbytesread += bytesread;
  2989 
  2990   bytesread = readData(handle, handle->buf, 4);
  2991   if (bytesread < 0)
  2992     return -1;
  2993   stsz->sampleCount = u32endian(*((mp4_u32 *)handle->buf));
  2994   totalbytesread += bytesread;
  2995 
  2996   switch (fieldsize)
  2997   {
  2998   case 4: /* Two entries in each byte */
  2999 
  3000     {
  3001       mp4_u32 i;
  3002 
  3003       stsz->entrySize = (mp4_u32 *)mp4malloc(stsz->sampleCount * sizeof(mp4_u32));
  3004       if (stsz->entrySize == NULL)
  3005         return -1;
  3006 
  3007       for (i = 0; i < (stsz->sampleCount + 1) / 2; i++)
  3008       {
  3009         bytesread = readData(handle, handle->buf, 1);
  3010         if (bytesread < 0)
  3011           return -1;
  3012 
  3013         totalbytesread += bytesread;
  3014 
  3015         stsz->entrySize[i * 2] = (mp4_u32)(handle->buf[0] >> 4);
  3016 
  3017         if (stsz->sampleCount % 2 == 0) /* Even number of samples */
  3018         {
  3019           stsz->entrySize[i * 2 + 1] = (mp4_u32)(handle->buf[0] & 0x0f);
  3020           continue;
  3021         }
  3022 
  3023         /* This condition is needed to avoid writing after the table */
  3024 
  3025         if (i == (stsz->sampleCount + 1) / 2 - 1) /* Last sample */
  3026         {
  3027         }
  3028         else
  3029           stsz->entrySize[i * 2 + 1] = (mp4_u32)(handle->buf[0] & 0x0f);
  3030       }
  3031     }
  3032 
  3033     break;
  3034 
  3035   case 8: /* One entry for each byte */
  3036 
  3037     {
  3038       mp4_u32 i;
  3039 
  3040       stsz->entrySize = (mp4_u32 *)mp4malloc(stsz->sampleCount * sizeof(mp4_u32));
  3041       if (stsz->entrySize == NULL)
  3042         return -1;
  3043 
  3044       for (i = 0; i < stsz->sampleCount; i++)
  3045       {
  3046         bytesread = readData(handle, handle->buf, 1);
  3047         if (bytesread < 0)
  3048           return -1;
  3049 
  3050         stsz->entrySize[i] = (mp4_u32)handle->buf[0];
  3051 
  3052         totalbytesread += bytesread;
  3053       }
  3054     }
  3055 
  3056     break;
  3057 
  3058   case 16: /* Each entry in 2 bytes */
  3059 
  3060     {
  3061       mp4_u32 i;
  3062 
  3063       stsz->entrySize = (mp4_u32 *)mp4malloc(stsz->sampleCount * sizeof(mp4_u32));
  3064       if (stsz->entrySize == NULL)
  3065         return -1;
  3066 
  3067       for (i = 0; i < stsz->sampleCount; i++)
  3068       {
  3069         bytesread = readData(handle, handle->buf, 2);
  3070         if (bytesread < 0)
  3071           return -1;
  3072 
  3073         stsz->entrySize[i] = (mp4_u32)u16endian(*((mp4_u16 *)handle->buf));
  3074 
  3075         totalbytesread += bytesread;
  3076       }
  3077     }
  3078 
  3079     break;
  3080 
  3081   default: /* Illegal fieldsize */
  3082 
  3083     return -1;
  3084   }
  3085 
  3086 
  3087   return totalbytesread;
  3088 }
  3089 
  3090 
  3091 /*
  3092  * Function:
  3093  *
  3094  *   mp4_i32 readSTSC(MP4HandleImp handle,
  3095  *                    sampleToChunkAtom *stsc)
  3096  *
  3097  * Description:
  3098  *
  3099  *   This function parses one STSC atom.
  3100  *
  3101  * Parameters:
  3102  *
  3103  *   handle             MP4 library handle
  3104  *   stsc               STSC pointer
  3105  *
  3106  * Return value:
  3107  *
  3108  *   Negative integer   Error
  3109  *   >= 0               Success. Value tells how many bytes were read.
  3110  *
  3111  */
  3112 mp4_i32 readSTSC(MP4HandleImp handle, sampleToChunkAtom *stsc)
  3113 {
  3114   mp4_i32 bytesread;
  3115   mp4_i32 totalbytesread = 0;
  3116   mp4_u32 i;
  3117 
  3118 
  3119   if ((stsc->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  3120     return -100;
  3121 
  3122   bytesread = readFullAtomHeader(handle, stsc->atomhdr);
  3123   if (bytesread < 0)
  3124     return -1;
  3125   totalbytesread += bytesread;
  3126 
  3127   if (stsc->atomhdr->type != ATOMTYPE_STSC)
  3128     return -1;
  3129 
  3130 
  3131   bytesread = readData(handle, handle->buf, 4);
  3132   if (bytesread < 0)
  3133     return -1;
  3134   stsc->entryCount = u32endian(*((mp4_u32 *)handle->buf));
  3135   totalbytesread += bytesread;
  3136 
  3137   if (stsc->entryCount)
  3138   {
  3139 	  stsc->firstChunk = (mp4_u32 *)mp4malloc(stsc->entryCount * sizeof(mp4_u32));
  3140 	  if (stsc->firstChunk == NULL)
  3141 	    return -1;
  3142 	  stsc->samplesPerChunk = (mp4_u32 *)mp4malloc(stsc->entryCount * sizeof(mp4_u32));
  3143 	  if (stsc->samplesPerChunk == NULL)
  3144 	    return -1;
  3145 	  stsc->sampleDescriptionIndex = (mp4_u32 *)mp4malloc(stsc->entryCount * sizeof(mp4_u32));
  3146 	  if (stsc->sampleDescriptionIndex == NULL)
  3147 	  {
  3148 		return -1;	  	
  3149 	  }
  3150 
  3151 	  for (i = 0; i < stsc->entryCount; i++)
  3152 	  {
  3153 	    bytesread = readData(handle, handle->buf, 12);
  3154 	    if (bytesread < 0)
  3155 	      return -1;
  3156 
  3157 	    stsc->firstChunk[i] = u32endian(*((mp4_u32 *)handle->buf));
  3158 	    stsc->samplesPerChunk[i] = u32endian(*((mp4_u32 *)(handle->buf+4)));
  3159 	    stsc->sampleDescriptionIndex[i] = u32endian(*((mp4_u32 *)(handle->buf+8)));
  3160 	    if ( stsc->sampleDescriptionIndex[i] > stsc->entryCount)
  3161 	    {
  3162 	    	return -1;
  3163 	    }
  3164 
  3165 	    totalbytesread += bytesread;
  3166 	  }
  3167   }
  3168   return totalbytesread;
  3169 }
  3170 
  3171 
  3172 /*
  3173  * Function:
  3174  *
  3175  *   mp4_i32 readSTCO(MP4HandleImp handle,
  3176  *                    chunkOffsetAtom *stco)
  3177  *
  3178  * Description:
  3179  *
  3180  *   This function parses one STCO atom.
  3181  *
  3182  * Parameters:
  3183  *
  3184  *   handle             MP4 library handle
  3185  *   stco               STCO pointer
  3186  *
  3187  * Return value:
  3188  *
  3189  *   Negative integer   Error
  3190  *   >= 0               Success. Value tells how many bytes were read.
  3191  *
  3192  */
  3193 mp4_i32 readSTCO(MP4HandleImp handle, chunkOffsetAtom *stco)
  3194 {
  3195   mp4_i32 bytesread;
  3196   mp4_i32 totalbytesread = 0;
  3197   mp4_u32  i;
  3198 
  3199 
  3200   if ((stco->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  3201     return -100;
  3202 
  3203   bytesread = readFullAtomHeader(handle, stco->atomhdr);
  3204   if (bytesread < 0)
  3205     return -1;
  3206   totalbytesread += bytesread;
  3207 
  3208   if (stco->atomhdr->type != ATOMTYPE_STCO)
  3209     return -1;
  3210 
  3211 
  3212   bytesread = readData(handle, handle->buf, 4);
  3213   if (bytesread < 0)
  3214     return -1;
  3215   stco->entryCount = u32endian(*((mp4_u32 *)handle->buf));
  3216   totalbytesread += bytesread;
  3217 
  3218   if (stco->entryCount)
  3219   {
  3220 	  // validate stco->entryCount before allocating chunkOffsetTable
  3221 	  if ( handle->moov->mvhd )
  3222 	    {
  3223 	    if ( handle->moov->mvhd->timeScale > 0 )
  3224 	        {
  3225 	        TUint magicNumberMaxSamplesInSec = MAXSAMPLESPERSECOND;
  3226 	        TUint maxSampleCount;
  3227 
  3228 	        if ( handle->moov->mvhd->atomhdr->version == 1 ) // 64bit duration
  3229 	            {
  3230 	            maxSampleCount = I64INT(handle->moov->mvhd->duration64 / TUint(handle->moov->mvhd->timeScale) + 1) * magicNumberMaxSamplesInSec;
  3231 	            }
  3232 	        else    // 32bit duration
  3233 	            {
  3234 	            maxSampleCount = TUint((TUint( handle->moov->mvhd->duration  ) / TUint(handle->moov->mvhd->timeScale) + 1)) * magicNumberMaxSamplesInSec;
  3235 	            }
  3236 
  3237 	        if ( maxSampleCount < stco->entryCount )
  3238 	            {
  3239 	            // corrupted 
  3240 	            return -1;
  3241 	            }
  3242 	        }
  3243 	    }
  3244 
  3245 	  stco->chunkOffset = (mp4_u32 *)mp4malloc(stco->entryCount * sizeof(mp4_u32));
  3246 	  if (stco->chunkOffset == NULL)
  3247 	    return -1;
  3248 
  3249 	  for (i = 0; i < stco->entryCount; i++)
  3250 	  {
  3251 	    bytesread = readData(handle, handle->buf, 4);
  3252 	    if (bytesread < 0)
  3253 	      return -1;
  3254 
  3255 	    stco->chunkOffset[i] = u32endian(*((mp4_u32 *)handle->buf));
  3256 
  3257 	    totalbytesread += bytesread;
  3258 	  }
  3259   }
  3260   return totalbytesread;
  3261 }
  3262 
  3263 
  3264 /*
  3265  * Function:
  3266  *
  3267  *   mp4_i32 readCO64(MP4HandleImp handle,
  3268  *                    chunkOffset64Atom *stco64)
  3269  *
  3270  * Description:
  3271  *
  3272  *   This function parses one CO64 atom.
  3273  *
  3274  * Parameters:
  3275  *
  3276  *   handle             MP4 library handle
  3277  *   stco64               CO64 pointer
  3278  *
  3279  * Return value:
  3280  *
  3281  *   Negative integer   Error
  3282  *   >= 0               Success. Value tells how many bytes were read.
  3283  *
  3284  */
  3285 mp4_i32 readCO64(MP4HandleImp handle, chunkOffset64Atom *stco64)
  3286 {
  3287   mp4_i32 bytesread;
  3288   mp4_i32 totalbytesread = 0;
  3289   mp4_u32 i;
  3290 
  3291 
  3292   if ((stco64->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  3293     return -100;
  3294 
  3295   bytesread = readFullAtomHeader(handle, stco64->atomhdr);
  3296   if (bytesread < 0)
  3297     return -1;
  3298   totalbytesread += bytesread;
  3299 
  3300   if (stco64->atomhdr->type != ATOMTYPE_CO64)
  3301     return -1;
  3302 
  3303 
  3304   bytesread = readData(handle, handle->buf, 4);
  3305   if (bytesread < 0)
  3306     return -1;
  3307   stco64->entryCount = u32endian(*((mp4_u32 *)handle->buf));
  3308   totalbytesread += bytesread;
  3309 
  3310   if ( stco64->entryCount )
  3311   {
  3312 	  stco64->chunkOffset = (mp4_u64 *)mp4malloc(stco64->entryCount * sizeof(mp4_u64));
  3313 	  if (stco64->chunkOffset == NULL)
  3314 	    return -1;
  3315 
  3316 	  for (i = 0; i < stco64->entryCount; i++)
  3317 	  {
  3318 	    bytesread = readData(handle, handle->buf, 8);
  3319 	    if (bytesread < 0)
  3320 	      return -1;
  3321 	    
  3322 	    stco64->chunkOffset[i] = u64endian(*((mp4_u64 *)(handle->buf)));
  3323 
  3324 	    totalbytesread += bytesread;
  3325 	  }
  3326   }
  3327   return totalbytesread;
  3328 }
  3329 
  3330 
  3331 /*
  3332  * Function:
  3333  *
  3334  *   mp4_i32 readMP4V(MP4HandleImp handle,
  3335  *                    visualSampleEntry *mp4v)
  3336  *
  3337  * Description:
  3338  *
  3339  *   This function parses one MP4V atom.
  3340  *
  3341  * Parameters:
  3342  *
  3343  *   handle             MP4 library handle
  3344  *   mp4v               MP4V pointer
  3345  *
  3346  * Return value:
  3347  *
  3348  *   Negative integer   Error
  3349  *   >= 0               Success. Value tells how many bytes were read.
  3350  *
  3351  */
  3352 mp4_i32 readMP4V(MP4HandleImp handle, visualSampleEntry *mp4v)
  3353 {
  3354   mp4_i32 bytesread;
  3355   mp4_i32 totalbytesread = 0;
  3356 
  3357 
  3358   if ((mp4v->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  3359     return -100;
  3360 
  3361   bytesread = readAtomHeader(handle, mp4v->atomhdr);
  3362   if (bytesread < 0)
  3363     return -1;
  3364   totalbytesread += bytesread;
  3365 
  3366   if (mp4v->atomhdr->type != ATOMTYPE_MP4V)
  3367     return -1;
  3368 
  3369 
  3370   bytesread = discardData(handle, 6);
  3371   if (bytesread < 0)
  3372     return -1;
  3373   totalbytesread += bytesread;
  3374 
  3375   bytesread = readData(handle, handle->buf, 2);
  3376   if (bytesread < 0)
  3377     return -1;
  3378   mp4v->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
  3379   totalbytesread += bytesread;
  3380 
  3381   bytesread = discardData(handle, 16);
  3382   if (bytesread < 0)
  3383     return -1;
  3384   totalbytesread += bytesread;
  3385 
  3386   bytesread = readData(handle, handle->buf, 2);
  3387   if (bytesread < 0)
  3388     return -1;
  3389   mp4v->width = u16endian(*((mp4_u16 *)handle->buf));
  3390   totalbytesread += bytesread;
  3391 
  3392   bytesread = readData(handle, handle->buf, 2);
  3393   if (bytesread < 0)
  3394     return -1;
  3395   mp4v->height = u16endian(*((mp4_u16 *)handle->buf));
  3396   totalbytesread += bytesread;
  3397 
  3398   bytesread = discardData(handle, 50);
  3399   if (bytesread < 0)
  3400     return -1;
  3401   totalbytesread += bytesread;
  3402 
  3403   if ((mp4v->esd = (ESDAtom *)mp4malloc(sizeof(ESDAtom))) == NULL)
  3404     return -100;
  3405 
  3406   bytesread = readESD(handle, mp4v->esd);
  3407   if (bytesread < 0)
  3408     return -1;
  3409   totalbytesread += bytesread;
  3410   
  3411   if ( totalbytesread < mp4v->atomhdr->size )
  3412   	{
  3413     bytesread = discardData(handle, mp4v->atomhdr->size - totalbytesread );
  3414   	if (bytesread < 0)
  3415   		{
  3416     	return -1;	  		
  3417   		}
  3418   	totalbytesread += bytesread;
  3419   	}  
  3420 
  3421   return totalbytesread;
  3422 }
  3423 
  3424 
  3425 /*
  3426  * Function:
  3427  *
  3428  *   mp4_i32 readMP4A(MP4HandleImp handle,
  3429  *                    audioSampleEntry *mp4a)
  3430  *
  3431  * Description:
  3432  *
  3433  *   This function parses one MP4A atom.
  3434  *
  3435  * Parameters:
  3436  *
  3437  *   handle             MP4 library handle
  3438  *   mp4a               MP4A pointer
  3439  *
  3440  * Return value:
  3441  *
  3442  *   Negative integer   Error
  3443  *   >= 0               Success. Value tells how many bytes were read.
  3444  *
  3445  */
  3446 mp4_i32 readMP4A(MP4HandleImp handle, audioSampleEntry *mp4a)
  3447 {
  3448   mp4_i32 bytesread;
  3449   mp4_i32 totalbytesread = 0;
  3450 
  3451 
  3452   if ((mp4a->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  3453     return -100;
  3454 
  3455   bytesread = readAtomHeader(handle, mp4a->atomhdr);
  3456   if (bytesread < 0)
  3457     return -1;
  3458   totalbytesread += bytesread;
  3459 
  3460   if (mp4a->atomhdr->type != ATOMTYPE_MP4A)
  3461     return -1;
  3462 
  3463 
  3464   bytesread = discardData(handle, 6);
  3465   if (bytesread < 0)
  3466     return -1;
  3467   totalbytesread += bytesread;
  3468 
  3469   bytesread = readData(handle, handle->buf, 2);
  3470   if (bytesread < 0)
  3471     return -1;
  3472   mp4a->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
  3473   totalbytesread += bytesread;
  3474 
  3475   bytesread = discardData(handle, 16);
  3476   if (bytesread < 0)
  3477     return -1;
  3478   totalbytesread += bytesread;
  3479 
  3480   bytesread = readData(handle, handle->buf, 2);
  3481   if (bytesread < 0)
  3482     return -1;
  3483   mp4a->timeScale = u16endian(*((mp4_u16 *)handle->buf));
  3484   totalbytesread += bytesread;
  3485 
  3486   bytesread = discardData(handle, 2);
  3487   if (bytesread < 0)
  3488     return -1;
  3489   totalbytesread += bytesread;
  3490 
  3491   if ((mp4a->esd = (ESDAtom *)mp4malloc(sizeof(ESDAtom))) == NULL)
  3492     return -100;
  3493 
  3494   bytesread = readESD(handle, mp4a->esd);
  3495   if (bytesread < 0)
  3496     return -1;
  3497   totalbytesread += bytesread;
  3498   
  3499   if ( totalbytesread < mp4a->atomhdr->size )
  3500   	{
  3501     bytesread = discardData(handle, mp4a->atomhdr->size - totalbytesread );
  3502   	if (bytesread < 0)
  3503   		{
  3504     	return -1;	  		
  3505   		}
  3506   	totalbytesread += bytesread;
  3507   	}
  3508 
  3509   return totalbytesread;
  3510 }
  3511 
  3512 
  3513 /*
  3514  * Function:
  3515  *
  3516  *   mp4_i32 readMP4S(MP4HandleImp handle,
  3517  *                    mpegSampleEntry *mp4s)
  3518  *
  3519  * Description:
  3520  *
  3521  *   This function parses one MP4S atom.
  3522  *
  3523  * Parameters:
  3524  *
  3525  *   handle             MP4 library handle
  3526  *   mp4s               MP4S pointer
  3527  *
  3528  * Return value:
  3529  *
  3530  *   Negative integer   Error
  3531  *   >= 0               Success. Value tells how many bytes were read.
  3532  *
  3533  */
  3534 mp4_i32 readMP4S(MP4HandleImp handle, mpegSampleEntry *mp4s)
  3535 {
  3536   mp4_i32 bytesread;
  3537   mp4_i32 totalbytesread = 0;
  3538 
  3539 
  3540   if ((mp4s->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  3541     return -100;
  3542 
  3543   bytesread = readAtomHeader(handle, mp4s->atomhdr);
  3544   if (bytesread < 0)
  3545     return -1;
  3546   totalbytesread += bytesread;
  3547 
  3548   if (mp4s->atomhdr->type != ATOMTYPE_MP4S)
  3549     return -1;
  3550 
  3551 
  3552   bytesread = discardData(handle, 6);
  3553   if (bytesread < 0)
  3554     return -1;
  3555   totalbytesread += bytesread;
  3556 
  3557   bytesread = readData(handle, handle->buf, 2);
  3558   if (bytesread < 0)
  3559     return -1;
  3560   mp4s->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
  3561   totalbytesread += bytesread;
  3562 
  3563   if ((mp4s->esd = (ESDAtom *)mp4malloc(sizeof(ESDAtom))) == NULL)
  3564     return -100;
  3565 
  3566   bytesread = readESD(handle, mp4s->esd);
  3567   if (bytesread < 0)
  3568     return -1;
  3569   totalbytesread += bytesread;
  3570   
  3571   if ( totalbytesread < mp4s->atomhdr->size )
  3572   	{
  3573     bytesread = discardData(handle, mp4s->atomhdr->size - totalbytesread );
  3574   	if (bytesread < 0)
  3575   		{
  3576     	return -1;	  		
  3577   		}
  3578   	totalbytesread += bytesread;
  3579   	}    
  3580 
  3581   return totalbytesread;
  3582 }
  3583 
  3584 
  3585 /*
  3586  * Function:
  3587  *
  3588  *   mp4_i32 readS263(MP4HandleImp handle,
  3589  *                    h263SampleEntry *s263)
  3590  *
  3591  * Description:
  3592  *
  3593  *   This function parses one S263 atom.
  3594  *
  3595  * Parameters:
  3596  *
  3597  *   handle             MP4 library handle
  3598  *   s263               S263 pointer
  3599  *
  3600  * Return value:
  3601  *
  3602  *   Negative integer   Error
  3603  *   >= 0               Success. Value tells how many bytes were read.
  3604  *
  3605  */
  3606 mp4_i32 readS263(MP4HandleImp handle, h263SampleEntry *s263)
  3607 {
  3608   mp4_i32 bytesread;
  3609   mp4_i32 totalbytesread = 0;
  3610 
  3611 
  3612   if ((s263->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  3613     return -100;
  3614 
  3615   bytesread = readAtomHeader(handle, s263->atomhdr);
  3616   if (bytesread < 0)
  3617     return -1;
  3618   totalbytesread += bytesread;
  3619 
  3620   if (s263->atomhdr->type != ATOMTYPE_S263)
  3621     return -1;
  3622 
  3623 
  3624   bytesread = discardData(handle, 6);
  3625   if (bytesread < 0)
  3626     return -1;
  3627   totalbytesread += bytesread;
  3628 
  3629   bytesread = readData(handle, handle->buf, 2);
  3630   if (bytesread < 0)
  3631     return -1;
  3632   s263->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
  3633   totalbytesread += bytesread;
  3634 
  3635   bytesread = discardData(handle, 16);
  3636   if (bytesread < 0)
  3637     return -1;
  3638   totalbytesread += bytesread;
  3639 
  3640   bytesread = readData(handle, handle->buf, 2);
  3641   if (bytesread < 0)
  3642     return -1;
  3643   s263->width = u16endian(*((mp4_u16 *)handle->buf));
  3644   totalbytesread += bytesread;
  3645 
  3646   bytesread = readData(handle, handle->buf, 2);
  3647   if (bytesread < 0)
  3648     return -1;
  3649   s263->height = u16endian(*((mp4_u16 *)handle->buf));
  3650   totalbytesread += bytesread;
  3651 
  3652   bytesread = discardData(handle, 50);
  3653   if (bytesread < 0)
  3654     return -1;
  3655   totalbytesread += bytesread;
  3656 
  3657   if ((s263->d263 = (h263SpecificAtom *)mp4malloc(sizeof(h263SpecificAtom))) == NULL)
  3658     return -100;
  3659 
  3660   bytesread = readD263(handle, s263->d263);
  3661   if (bytesread < 0)
  3662     return -1;
  3663   totalbytesread += bytesread;
  3664   
  3665   if ( totalbytesread < s263->atomhdr->size )
  3666   	{
  3667     bytesread = discardData(handle, s263->atomhdr->size - totalbytesread );
  3668   	if (bytesread < 0)
  3669   		{
  3670     	return -1;	  		
  3671   		}
  3672   	totalbytesread += bytesread;
  3673   	}      
  3674 
  3675   return totalbytesread;
  3676 }
  3677 
  3678 
  3679 /*
  3680  * Function:
  3681  *
  3682  *   mp4_i32 readSAMR(MP4HandleImp handle,
  3683  *                    amrSampleEntry *samr)
  3684  *
  3685  * Description:
  3686  *
  3687  *   This function parses one SAMR atom.
  3688  *
  3689  * Parameters:
  3690  *
  3691  *   handle             MP4 library handle
  3692  *   samr               SAMR pointer
  3693  *
  3694  * Return value:
  3695  *
  3696  *   Negative integer   Error
  3697  *   >= 0               Success. Value tells how many bytes were read.
  3698  *
  3699  */
  3700 mp4_i32 readSAMR(MP4HandleImp handle, amrSampleEntry *samr)
  3701 {
  3702   mp4_i32 bytesread;
  3703   mp4_i32 totalbytesread = 0;
  3704 
  3705 
  3706   if ((samr->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  3707     return -100;
  3708 
  3709   bytesread = readAtomHeader(handle, samr->atomhdr);
  3710   if (bytesread < 0)
  3711     return -1;
  3712   totalbytesread += bytesread;
  3713 
  3714   if (samr->atomhdr->type != ATOMTYPE_SAMR)
  3715     return -1;
  3716 
  3717 
  3718   bytesread = discardData(handle, 6);
  3719   if (bytesread < 0)
  3720     return -1;
  3721   totalbytesread += bytesread;
  3722 
  3723   bytesread = readData(handle, handle->buf, 2);
  3724   if (bytesread < 0)
  3725     return -1;
  3726   samr->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
  3727   totalbytesread += bytesread;
  3728 
  3729   bytesread = discardData(handle, 16);
  3730   if (bytesread < 0)
  3731     return -1;
  3732   totalbytesread += bytesread;
  3733 
  3734   bytesread = readData(handle, handle->buf, 2);
  3735   if (bytesread < 0)
  3736     return -1;
  3737   samr->timeScale = u16endian(*((mp4_u16 *)handle->buf));
  3738   totalbytesread += bytesread;
  3739 
  3740   bytesread = discardData(handle, 2);
  3741   if (bytesread < 0)
  3742     return -1;
  3743   totalbytesread += bytesread;
  3744 
  3745   if ((samr->damr = (amrDecSpecStruc *)mp4malloc(sizeof(amrDecSpecStruc))) == NULL)
  3746     return -100;
  3747 
  3748   bytesread = readDAMR(handle, samr->damr);
  3749   if (bytesread < 0)
  3750     return -1;
  3751   totalbytesread += bytesread;
  3752   
  3753   if ( totalbytesread < samr->atomhdr->size )
  3754   	{
  3755     bytesread = discardData(handle, samr->atomhdr->size - totalbytesread );
  3756   	if (bytesread < 0)
  3757   		{
  3758     	return -1;	  		
  3759   		}
  3760   	totalbytesread += bytesread;
  3761   	}      
  3762 
  3763   return totalbytesread;
  3764 }
  3765 
  3766 
  3767 /*
  3768  * Function:
  3769  *
  3770  *   mp4_i32 readSAWB(MP4HandleImp handle,
  3771  *                    amrSampleEntry *sawb)
  3772  *
  3773  * Description:
  3774  *
  3775  *   This function parses one SAWB atom.
  3776  *
  3777  * Parameters:
  3778  *
  3779  *   handle             MP4 library handle
  3780  *   sawb               SAWB pointer
  3781  *
  3782  * Return value:
  3783  *
  3784  *   Negative integer   Error
  3785  *   >= 0               Success. Value tells how many bytes were read.
  3786  *
  3787  */
  3788 mp4_i32 readSAWB(MP4HandleImp handle, amrSampleEntry *sawb)
  3789 {
  3790   mp4_i32 bytesread;
  3791   mp4_i32 totalbytesread = 0;
  3792 
  3793 
  3794   if ((sawb->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  3795     return -100;
  3796 
  3797   bytesread = readAtomHeader(handle, sawb->atomhdr);
  3798   if (bytesread < 0)
  3799     return -1;
  3800   totalbytesread += bytesread;
  3801 
  3802   if (sawb->atomhdr->type != ATOMTYPE_SAWB)
  3803     return -1;
  3804 
  3805 
  3806   bytesread = discardData(handle, 6);
  3807   if (bytesread < 0)
  3808     return -1;
  3809   totalbytesread += bytesread;
  3810 
  3811   bytesread = readData(handle, handle->buf, 2);
  3812   if (bytesread < 0)
  3813     return -1;
  3814   sawb->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
  3815   totalbytesread += bytesread;
  3816 
  3817   bytesread = discardData(handle, 16);
  3818   if (bytesread < 0)
  3819     return -1;
  3820   totalbytesread += bytesread;
  3821 
  3822   bytesread = readData(handle, handle->buf, 2);
  3823   if (bytesread < 0)
  3824     return -1;
  3825   sawb->timeScale = u16endian(*((mp4_u16 *)handle->buf));
  3826   totalbytesread += bytesread;
  3827 
  3828   bytesread = discardData(handle, 2);
  3829   if (bytesread < 0)
  3830     return -1;
  3831   totalbytesread += bytesread;
  3832 
  3833   if ((sawb->damr = (amrDecSpecStruc *)mp4malloc(sizeof(amrDecSpecStruc))) == NULL)
  3834     return -100;
  3835 
  3836   bytesread = readDAMR(handle, sawb->damr);
  3837   if (bytesread < 0)
  3838     return -1;
  3839   totalbytesread += bytesread;
  3840   
  3841   if ( totalbytesread < sawb->atomhdr->size )
  3842   	{
  3843     bytesread = discardData(handle, sawb->atomhdr->size - totalbytesread );
  3844   	if (bytesread < 0)
  3845   		{
  3846     	return -1;	  		
  3847   		}
  3848   	totalbytesread += bytesread;
  3849   	}      
  3850 
  3851   return totalbytesread;
  3852 }
  3853 
  3854 
  3855 /*
  3856  * Function:
  3857  *
  3858  *   mp4_i32 readESD(MP4HandleImp handle,
  3859  *                   ESDAtom *esd)
  3860  *
  3861  * Description:
  3862  *
  3863  *   This function parses one ESD atom.
  3864  *
  3865  * Parameters:
  3866  *
  3867  *   handle             MP4 library handle
  3868  *   esd                ESD pointer
  3869  *
  3870  * Return value:
  3871  *
  3872  *   Negative integer   Error
  3873  *   >= 0               Success. Value tells how many bytes were read.
  3874  *
  3875  */
  3876 mp4_i32 readESD(MP4HandleImp handle, ESDAtom *esd)
  3877 {
  3878   mp4_i32 bytesread;
  3879   mp4_i32 totalbytesread = 0;
  3880   mp4_i32 decConfDescrBytesRead = 0;
  3881 
  3882 
  3883   if ((esd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  3884     return -100;
  3885 
  3886   bytesread = readFullAtomHeader(handle, esd->atomhdr);
  3887   if (bytesread < 0)
  3888     return -1;
  3889   totalbytesread += bytesread;
  3890 
  3891   if (esd->atomhdr->type != ATOMTYPE_ESD)
  3892     return -1;
  3893 
  3894 
  3895   bytesread = readData(handle, handle->buf, 1);
  3896   if (bytesread < 0)
  3897     return -1;
  3898   esd->esDescrTag = handle->buf[0];
  3899   totalbytesread += bytesread;
  3900   if (esd->esDescrTag != 3) /* ES_DescrTag == 3 */
  3901     return -1;
  3902 
  3903   esd->size = 0;
  3904   do
  3905   {
  3906     mp4_u8 c;
  3907 
  3908     bytesread = readData(handle, handle->buf, 1);
  3909     if (bytesread < 0)
  3910       return -1;
  3911     c = (mp4_u8)(handle->buf[0] & 0x7f);
  3912     esd->size = (esd->size << 7) | c;
  3913     totalbytesread += bytesread;
  3914   }
  3915   while (handle->buf[0] & 0x80);
  3916 
  3917   bytesread = readData(handle, handle->buf, 2);
  3918   if (bytesread < 0)
  3919     return -1;
  3920   esd->ESID = u16endian(*((mp4_u16 *)handle->buf));
  3921   totalbytesread += bytesread;
  3922 
  3923   bytesread = readData(handle, handle->buf, 1);
  3924   if (bytesread < 0)
  3925     return -1;
  3926   esd->flags = handle->buf[0];
  3927   totalbytesread += bytesread;
  3928 
  3929   if (esd->flags & 0x80) /* Stream Dependence flag has been set */
  3930   {
  3931     bytesread = readData(handle, handle->buf, 2);
  3932     if (bytesread < 0)
  3933       return -1;
  3934     esd->dependsOnESID = u16endian(*((mp4_u16 *)handle->buf));
  3935     totalbytesread += bytesread;
  3936   }
  3937 
  3938   if (esd->flags & 0x40) /* URL flag has been set */
  3939   {
  3940     bytesread = readData(handle, handle->buf, 1);
  3941     if (bytesread < 0)
  3942       return -1;
  3943     esd->URLLength = handle->buf[0];
  3944     totalbytesread += bytesread;
  3945 
  3946     bytesread = discardData(handle, esd->URLLength);
  3947     if (bytesread < 0)
  3948       return -1;
  3949     totalbytesread += bytesread;
  3950   }
  3951 
  3952   if (esd->flags & 0x20) /* OCR stream flag has been set */
  3953   {
  3954     bytesread = readData(handle, handle->buf, 2);
  3955     if (bytesread < 0)
  3956       return -1;
  3957     esd->OCRESID = u16endian(*((mp4_u16 *)handle->buf));
  3958     totalbytesread += bytesread;
  3959   }
  3960 
  3961   bytesread = readData(handle, handle->buf, 1);
  3962   if (bytesread < 0)
  3963     return -1;
  3964   esd->decConfDescrTag = handle->buf[0];
  3965   totalbytesread += bytesread;
  3966   if (esd->decConfDescrTag != 4) /* DecoderConfigDescrTag == 4 */
  3967     return -1;
  3968 
  3969   esd->decConfDescrSize = 0;
  3970   do
  3971   {
  3972     mp4_u8 c;
  3973 
  3974     bytesread = readData(handle, handle->buf, 1);
  3975     if (bytesread < 0)
  3976       return -1;
  3977     c = (mp4_u8)(handle->buf[0] & 0x7f);
  3978     esd->decConfDescrSize = (esd->decConfDescrSize << 7) | c;
  3979     totalbytesread += bytesread;
  3980   }
  3981   while (handle->buf[0] & 0x80);
  3982 
  3983   bytesread = readData(handle, handle->buf, 1);
  3984   if (bytesread < 0)
  3985     return -1;
  3986   esd->objectTypeIndication = handle->buf[0];
  3987   totalbytesread += bytesread;
  3988   decConfDescrBytesRead += bytesread;
  3989 
  3990   bytesread = readData(handle, handle->buf, 1);
  3991   if (bytesread < 0)
  3992     return -1;
  3993   esd->stream = handle->buf[0];
  3994   totalbytesread += bytesread;
  3995   decConfDescrBytesRead += bytesread;
  3996 
  3997   bytesread = readData(handle, handle->buf, 3);
  3998   if (bytesread < 0)
  3999     return -1;
  4000   esd->bufferSizeDB = ((mp4_u32)handle->buf[0]) << 16 |
  4001                       ((mp4_u32)handle->buf[1]) << 8 |
  4002                       ((mp4_u32)handle->buf[2]);
  4003   totalbytesread += bytesread;
  4004   decConfDescrBytesRead += bytesread;
  4005 
  4006   bytesread = readData(handle, handle->buf, 4);
  4007   if (bytesread < 0)
  4008     return -1;
  4009   esd->maxBitrate = u32endian(*((mp4_u32 *)handle->buf));
  4010   totalbytesread += bytesread;
  4011   decConfDescrBytesRead += bytesread;
  4012 
  4013   bytesread = readData(handle, handle->buf, 4);
  4014   if (bytesread < 0)
  4015     return -1;
  4016   esd->avgBitrate = u32endian(*((mp4_u32 *)handle->buf));
  4017   totalbytesread += bytesread;
  4018   decConfDescrBytesRead += bytesread;
  4019 
  4020   if ((mp4_u32)decConfDescrBytesRead < esd->decConfDescrSize)
  4021   {
  4022     bytesread = readData(handle, handle->buf, 1);
  4023     if (bytesread < 0)
  4024       return -1;
  4025     esd->decSpecificInfoTag = handle->buf[0];
  4026     totalbytesread += bytesread;
  4027     decConfDescrBytesRead += bytesread;
  4028     if (esd->decSpecificInfoTag != 5) /* DecSpecificInfoTag == 5 */
  4029     {
  4030       bytesread = discardData(handle, esd->decConfDescrSize - decConfDescrBytesRead);
  4031       if (bytesread < 0)
  4032         return -1;
  4033       totalbytesread += bytesread;
  4034     }
  4035     else
  4036     {
  4037       esd->decSpecificInfoSize = 0;
  4038       do
  4039       {
  4040         mp4_u8 c;
  4041 
  4042         bytesread = readData(handle, handle->buf, 1);
  4043         if (bytesread < 0)
  4044           return -1;
  4045         c = (mp4_u8)(handle->buf[0] & 0x7f);
  4046         esd->decSpecificInfoSize = (esd->decSpecificInfoSize << 7) | c;
  4047         totalbytesread += bytesread;
  4048       }
  4049       while (handle->buf[0] & 0x80);
  4050 
  4051       if(esd->decSpecificInfoSize)
  4052       {
  4053         if ((esd->decSpecificInfo = (mp4_u8 *)mp4malloc(esd->decSpecificInfoSize)) == NULL)
  4054           return -100;
  4055 
  4056         bytesread = readData(handle, esd->decSpecificInfo, esd->decSpecificInfoSize);
  4057         if (bytesread < 0)
  4058           return -1;
  4059         totalbytesread += bytesread;
  4060       }
  4061     }
  4062   }
  4063 
  4064   bytesread = discardData(handle, esd->atomhdr->size - totalbytesread);
  4065   if (bytesread < 0)
  4066     return -1;
  4067   totalbytesread += bytesread;
  4068 
  4069   return totalbytesread;
  4070 }
  4071 
  4072 
  4073 /*
  4074  * Function:
  4075  *
  4076  *   mp4_i32 readD263(MP4HandleImp handle,
  4077  *                    h263SpecificAtom *d263)
  4078  *
  4079  * Description:
  4080  *
  4081  *   This function parses one D263 atom.
  4082  *
  4083  * Parameters:
  4084  *
  4085  *   handle             MP4 library handle
  4086  *   d263               D263 pointer
  4087  *
  4088  * Return value:
  4089  *
  4090  *   Negative integer   Error
  4091  *   >= 0               Success. Value tells how many bytes were read.
  4092  *
  4093  */
  4094 mp4_i32 readD263(MP4HandleImp handle, h263SpecificAtom *d263)
  4095 {
  4096   mp4_i32 bytesread;
  4097   mp4_i32 totalbytesread = 0;
  4098 
  4099 
  4100   if ((d263->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  4101     return -100;
  4102 
  4103   bytesread = readAtomHeader(handle, d263->atomhdr);
  4104   if (bytesread < 0)
  4105     return -1;
  4106   totalbytesread += bytesread;
  4107 
  4108   if (d263->atomhdr->type != ATOMTYPE_D263)
  4109     return -1;
  4110 
  4111 
  4112   bytesread = readData(handle, handle->buf, 4);
  4113   if (bytesread < 0)
  4114     return -1;
  4115   d263->vendor = u32endian(*((mp4_u32 *)handle->buf));
  4116   totalbytesread += bytesread;
  4117 
  4118   bytesread = readData(handle, handle->buf, 1);
  4119   if (bytesread < 0)
  4120     return -1;
  4121   d263->decoderVersion = handle->buf[0];
  4122   totalbytesread += bytesread;
  4123 
  4124   bytesread = readData(handle, handle->buf, 1);
  4125   if (bytesread < 0)
  4126     return -1;
  4127   d263->h263Level = handle->buf[0];
  4128   totalbytesread += bytesread;
  4129 
  4130   bytesread = readData(handle, handle->buf, 1);
  4131   if (bytesread < 0)
  4132     return -1;
  4133   d263->h263Profile = handle->buf[0];
  4134   totalbytesread += bytesread;
  4135 
  4136   /* Check for the bitrate atom */
  4137 
  4138   while ((mp4_u32)totalbytesread < d263->atomhdr->size)
  4139   {
  4140     mp4_u32 type;
  4141 
  4142 
  4143     if (peekData(handle, handle->buf, 8) < 0)
  4144       return -1;
  4145 
  4146     type = u32endian(*((mp4_u32 *)(handle->buf+4)));
  4147 
  4148     switch (type)
  4149     {
  4150     case ATOMTYPE_BITR:
  4151 
  4152       if (d263->bitr) /* BITR has already been read, more than one is not allowed */
  4153         return -1;
  4154 
  4155       if ((d263->bitr = (bitrateAtom *)mp4malloc(sizeof(bitrateAtom))) == NULL)
  4156         return -100;
  4157 
  4158       bytesread = readBITR(handle, d263->bitr);
  4159       if (bytesread < 0)
  4160         return -1;
  4161       totalbytesread += bytesread;
  4162 
  4163       break;
  4164 
  4165     default: /* Other atoms are not needed */
  4166 
  4167       bytesread = readUnknown(handle);
  4168       if (bytesread < 0)
  4169         return -1;
  4170       totalbytesread += bytesread;
  4171 
  4172       break;
  4173     }
  4174   }
  4175 
  4176   return totalbytesread;
  4177 }
  4178 
  4179 
  4180 /*
  4181  * Function:
  4182  *
  4183  *   mp4_i32 readBITR(MP4HandleImp handle,
  4184  *                    bitrateAtom *d263)
  4185  *
  4186  * Description:
  4187  *
  4188  *   This function parses one BITR atom.
  4189  *
  4190  * Parameters:
  4191  *
  4192  *   handle             MP4 library handle
  4193  *   bitr               BITR pointer
  4194  *
  4195  * Return value:
  4196  *
  4197  *   Negative integer   Error
  4198  *   >= 0               Success. Value tells how many bytes were read.
  4199  *
  4200  */
  4201 mp4_i32 readBITR(MP4HandleImp handle, bitrateAtom *bitr)
  4202 {
  4203   mp4_i32 bytesread;
  4204   mp4_i32 totalbytesread = 0;
  4205 
  4206 
  4207   if ((bitr->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  4208     return -100;
  4209 
  4210   bytesread = readAtomHeader(handle, bitr->atomhdr);
  4211   if (bytesread < 0)
  4212     return -1;
  4213   totalbytesread += bytesread;
  4214 
  4215   if (bitr->atomhdr->type != ATOMTYPE_BITR)
  4216     return -1;
  4217 
  4218 
  4219   bytesread = readData(handle, handle->buf, 4);
  4220   if (bytesread < 0)
  4221     return -1;
  4222   bitr->avgBitrate = u32endian(*((mp4_u32 *)handle->buf));
  4223   totalbytesread += bytesread;
  4224 
  4225   bytesread = readData(handle, handle->buf, 4);
  4226   if (bytesread < 0)
  4227     return -1;
  4228   bitr->maxBitrate = u32endian(*((mp4_u32 *)handle->buf));
  4229   totalbytesread += bytesread;
  4230 
  4231   return totalbytesread;
  4232 }
  4233 
  4234 
  4235 /*
  4236  * Function:
  4237  *
  4238  *   mp4_i32 readDAMR(MP4HandleImp handle,
  4239  *                    amrDecSpecStruc *damr)
  4240  *
  4241  * Description:
  4242  *
  4243  *   This function parses one DAMR atom.
  4244  *
  4245  * Parameters:
  4246  *
  4247  *   handle             MP4 library handle
  4248  *   damr               DAMR pointer
  4249  *
  4250  * Return value:
  4251  *
  4252  *   Negative integer   Error
  4253  *   >= 0               Success. Value tells how many bytes were read.
  4254  *
  4255  */
  4256 mp4_i32 readDAMR(MP4HandleImp handle, amrDecSpecStruc *damr)
  4257 {
  4258   mp4_i32 bytesread;
  4259   mp4_i32 totalbytesread = 0;
  4260 
  4261 
  4262   if ((damr->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  4263     return -100;
  4264 
  4265   bytesread = readAtomHeader(handle, damr->atomhdr);
  4266   if (bytesread < 0)
  4267     return -1;
  4268   totalbytesread += bytesread;
  4269 
  4270   if (damr->atomhdr->type != ATOMTYPE_DAMR)
  4271     return -1;
  4272 
  4273 
  4274   bytesread = readData(handle, handle->buf, 4);
  4275   if (bytesread < 0)
  4276     return -1;
  4277   damr->vendor = u32endian(*((mp4_u32 *)handle->buf));
  4278   totalbytesread += bytesread;
  4279 
  4280   bytesread = readData(handle, handle->buf, 1);
  4281   if (bytesread < 0)
  4282     return -1;
  4283   damr->decoderVersion = handle->buf[0];
  4284   totalbytesread += bytesread;
  4285 
  4286   bytesread = readData(handle, handle->buf, 2);
  4287   if (bytesread < 0)
  4288     return -1;
  4289   damr->modeSet = u16endian(*((mp4_u16 *)handle->buf));
  4290   totalbytesread += bytesread;
  4291 
  4292   bytesread = readData(handle, handle->buf, 1);
  4293   if (bytesread < 0)
  4294     return -1;
  4295   damr->modeChangePeriod = handle->buf[0];
  4296   totalbytesread += bytesread;
  4297 
  4298   bytesread = readData(handle, handle->buf, 1);
  4299   if (bytesread < 0)
  4300     return -1;
  4301   damr->framesPerSample = handle->buf[0];
  4302   totalbytesread += bytesread;
  4303 
  4304   return totalbytesread;
  4305 }
  4306 
  4307 
  4308 /*
  4309  * Function:
  4310  *
  4311  *   mp4_i32 freeFTYP(MP4HandleImp handle)
  4312  *
  4313  * Description:
  4314  *
  4315  *   This function frees memory for FTYP atom.
  4316  *
  4317  * Parameters:
  4318  *
  4319  *   ftyp       FTYP atom pointer
  4320  *
  4321  * Return value:
  4322  *
  4323  *   0          Success
  4324  *   Negative   Error
  4325  *
  4326  */
  4327 mp4_i32 freeFTYP(fileTypeAtom *ftyp)
  4328 {
  4329   if (ftyp)
  4330   {
  4331     if (freeAtomHeader(ftyp->atomhdr) < 0)
  4332       return -1;
  4333     if (ftyp->compatibleBrands)
  4334       mp4free(ftyp->compatibleBrands);
  4335 
  4336     mp4free(ftyp);
  4337   }
  4338 
  4339   return 0;
  4340 }
  4341 
  4342 
  4343 /*
  4344  * Function:
  4345  *
  4346  *   mp4_i32 freeMOOV(movieAtom *moov)
  4347  *
  4348  * Description:
  4349  *
  4350  *   This function frees memory for MOOV atom.
  4351  *
  4352  * Parameters:
  4353  *
  4354  *   moov       MOOV atom pointer
  4355  *
  4356  * Return value:
  4357  *
  4358  *   0          Success
  4359  *   Negative   Error
  4360  *
  4361  */
  4362 mp4_i32 freeMOOV(movieAtom *moov)
  4363 {
  4364   if (moov)
  4365   {
  4366     if (freeAtomHeader(moov->atomhdr) < 0)
  4367       return -1;
  4368     if (freeMVHD(moov->mvhd) < 0)
  4369       return -1;
  4370     if (freeTRAK(moov->trakAudio) < 0)
  4371       return -1;
  4372     if (freeTRAK(moov->trakVideo) < 0)
  4373       return -1;
  4374     if (freeIODS(moov->iods) < 0)
  4375       return -1;
  4376     if (freeUDTA(moov->udta) < 0)
  4377       return -1;
  4378     if (freeMETA(moov->meta) < 0)
  4379       return -1;
  4380 
  4381     mp4free(moov);
  4382   }
  4383 
  4384   return 0;
  4385 }
  4386 
  4387 
  4388 /*
  4389  * Function:
  4390  *
  4391  *   mp4_i32 freeAtomHeader(atomHeader *atomhdr)
  4392  *
  4393  * Description:
  4394  *
  4395  *   This function frees memory for atom header.
  4396  *
  4397  * Parameters:
  4398  *
  4399  *   atomhdr    atom header pointer
  4400  *
  4401  * Return value:
  4402  *
  4403  *   0          Success
  4404  *   Negative   Error
  4405  *
  4406  */
  4407 mp4_i32 freeAtomHeader(atomHeader *atomhdr)
  4408 {
  4409   if (atomhdr)
  4410     mp4free(atomhdr);
  4411 
  4412   return 0;
  4413 }
  4414 
  4415 
  4416 /*
  4417  * Function:
  4418  *
  4419  *   mp4_i32 freeMVHD(movieHeaderAtom *mvhd)
  4420  *
  4421  * Description:
  4422  *
  4423  *   This function frees memory for MVHD atom.
  4424  *
  4425  * Parameters:
  4426  *
  4427  *   mvhd       MVHD atom pointer
  4428  *
  4429  * Return value:
  4430  *
  4431  *   0          Success
  4432  *   Negative   Error
  4433  *
  4434  */
  4435 mp4_i32 freeMVHD(movieHeaderAtom *mvhd)
  4436 {
  4437   if (mvhd)
  4438   {
  4439     if (freeAtomHeader(mvhd->atomhdr) < 0)
  4440       return -1;
  4441 
  4442     mp4free(mvhd);
  4443   }
  4444 
  4445   return 0;
  4446 }
  4447 
  4448 
  4449 /*
  4450  * Function:
  4451  *
  4452  *   mp4_i32 freeTRAK(trackAtom *trak)
  4453  *
  4454  * Description:
  4455  *
  4456  *   This function frees memory for TRAK atom.
  4457  *
  4458  * Parameters:
  4459  *
  4460  *   trak       TRAK atom pointer
  4461  *
  4462  * Return value:
  4463  *
  4464  *   0          Success
  4465  *   Negative   Error
  4466  *
  4467  */
  4468 mp4_i32 freeTRAK(trackAtom *trak)
  4469 {
  4470   if (trak)
  4471   {
  4472     if (freeAtomHeader(trak->atomhdr) < 0)
  4473       return -1;
  4474     if (freeTKHD(trak->tkhd) < 0)
  4475       return -1;
  4476     if (freeTREF(trak->tref) < 0)
  4477       return -1;
  4478     if (freeEDTS(trak->edts) < 0)
  4479       return -1;
  4480     if (freeMDIA(trak->mdia) < 0)
  4481       return -1;
  4482     if (freeUDTA(trak->udta) < 0)
  4483       return -1;
  4484 
  4485     mp4free(trak);
  4486   }
  4487 
  4488   return 0;
  4489 }
  4490 
  4491 
  4492 /*
  4493  * Function:
  4494  *
  4495  *   mp4_i32 freeTKHD(trackHeaderAtom *tkhd)
  4496  *
  4497  * Description:
  4498  *
  4499  *   This function frees memory for TKHD atom.
  4500  *
  4501  * Parameters:
  4502  *
  4503  *   tkhd       TKHD atom pointer
  4504  *
  4505  * Return value:
  4506  *
  4507  *   0          Success
  4508  *   Negative   Error
  4509  *
  4510  */
  4511 mp4_i32 freeTKHD(trackHeaderAtom *tkhd)
  4512 {
  4513   if (tkhd)
  4514   {
  4515     if (freeAtomHeader(tkhd->atomhdr) < 0)
  4516       return -1;
  4517 
  4518     mp4free(tkhd);
  4519   }
  4520 
  4521   return 0;
  4522 }
  4523 
  4524 
  4525 /*
  4526  * Function:
  4527  *
  4528  *   mp4_i32 freeTREF(trackReferenceAtom *tref)
  4529  *
  4530  * Description:
  4531  *
  4532  *   This function frees memory for TREF atom.
  4533  *
  4534  * Parameters:
  4535  *
  4536  *   tref       TREF atom pointer
  4537  *
  4538  * Return value:
  4539  *
  4540  *   0          Success
  4541  *   Negative   Error
  4542  *
  4543  */
  4544 mp4_i32 freeTREF(trackReferenceAtom *tref)
  4545 {
  4546   if (tref)
  4547   {
  4548     if (freeAtomHeader(tref->atomhdr) < 0)
  4549       return -1;
  4550 
  4551     mp4free(tref);
  4552   }
  4553 
  4554   return 0;
  4555 }
  4556 
  4557 
  4558 /*
  4559  * Function:
  4560  *
  4561  *   mp4_i32 freeEDTS(editListContainerAtom *edts)
  4562  *
  4563  * Description:
  4564  *
  4565  *   This function frees memory for EDTS atom.
  4566  *
  4567  * Parameters:
  4568  *
  4569  *   edts       EDTS atom pointer
  4570  *
  4571  * Return value:
  4572  *
  4573  *   0          Success
  4574  *   Negative   Error
  4575  *
  4576  */
  4577 mp4_i32 freeEDTS(editListContainerAtom *edts)
  4578 {
  4579   if (edts)
  4580   {
  4581     if (freeAtomHeader(edts->atomhdr) < 0)
  4582       return -1;
  4583 
  4584     mp4free(edts);
  4585   }
  4586 
  4587   return 0;
  4588 }
  4589 
  4590 
  4591 /*
  4592  * Function:
  4593  *
  4594  *   mp4_i32 freeMDIA(mediaAtom *mdia)
  4595  *
  4596  * Description:
  4597  *
  4598  *   This function frees memory for MDIA atom.
  4599  *
  4600  * Parameters:
  4601  *
  4602  *   mdia       MDIA atom pointer
  4603  *
  4604  * Return value:
  4605  *
  4606  *   0          Success
  4607  *   Negative   Error
  4608  *
  4609  */
  4610 mp4_i32 freeMDIA(mediaAtom *mdia)
  4611 {
  4612   if (mdia)
  4613   {
  4614     if (freeAtomHeader(mdia->atomhdr) < 0)
  4615       return -1;
  4616     if (freeMDHD(mdia->mdhd) < 0)
  4617       return -1;
  4618     if (freeHDLR(mdia->hdlr) < 0)
  4619       return -1;
  4620     if (freeMINF(mdia->minf) < 0)
  4621       return -1;
  4622 
  4623     mp4free(mdia);
  4624   }
  4625 
  4626   return 0;
  4627 }
  4628 
  4629 
  4630 /*
  4631  * Function:
  4632  *
  4633  *   mp4_i32 freeMDHD(mediaHeaderAtom *mdhd)
  4634  *
  4635  * Description:
  4636  *
  4637  *   This function frees memory for MDHD atom.
  4638  *
  4639  * Parameters:
  4640  *
  4641  *   mdhd       MDHD atom pointer
  4642  *
  4643  * Return value:
  4644  *
  4645  *   0          Success
  4646  *   Negative   Error
  4647  *
  4648  */
  4649 mp4_i32 freeMDHD(mediaHeaderAtom *mdhd)
  4650 {
  4651   if (mdhd)
  4652   {
  4653     if (freeAtomHeader(mdhd->atomhdr) < 0)
  4654       return -1;
  4655 
  4656     mp4free(mdhd);
  4657   }
  4658 
  4659   return 0;
  4660 }
  4661 
  4662 
  4663 /*
  4664  * Function:
  4665  *
  4666  *   mp4_i32 freeHDLR(handlerAtom *hdlr)
  4667  *
  4668  * Description:
  4669  *
  4670  *   This function frees memory for HDLR atom.
  4671  *
  4672  * Parameters:
  4673  *
  4674  *   hdlr       HDLR atom pointer
  4675  *
  4676  * Return value:
  4677  *
  4678  *   0          Success
  4679  *   Negative   Error
  4680  *
  4681  */
  4682 mp4_i32 freeHDLR(handlerAtom *hdlr)
  4683 {
  4684   if (hdlr)
  4685   {
  4686     if (freeAtomHeader(hdlr->atomhdr) < 0)
  4687       return -1;
  4688     if (hdlr->name)
  4689       mp4free(hdlr->name);
  4690 
  4691     mp4free(hdlr);
  4692   }
  4693 
  4694   return 0;
  4695 }
  4696 
  4697 
  4698 /*
  4699  * Function:
  4700  *
  4701  *   mp4_i32 freeMINF(mediaInformationAtom *minf)
  4702  *
  4703  * Description:
  4704  *
  4705  *   This function frees memory for MINF atom.
  4706  *
  4707  * Parameters:
  4708  *
  4709  *   minf       MINF atom pointer
  4710  *
  4711  * Return value:
  4712  *
  4713  *   0          Success
  4714  *   Negative   Error
  4715  *
  4716  */
  4717 mp4_i32 freeMINF(mediaInformationAtom *minf)
  4718 {
  4719   if (minf)
  4720   {
  4721     if (freeAtomHeader(minf->atomhdr) < 0)
  4722       return -1;
  4723     if (freeVMHD(minf->vmhd) < 0)
  4724       return -1;
  4725     if (freeSMHD(minf->smhd) < 0)
  4726       return -1;
  4727     if (freeDINF(minf->dinf) < 0)
  4728       return -1;
  4729     if (freeSTBL(minf->stbl) < 0)
  4730       return -1;
  4731 
  4732     mp4free(minf);
  4733   }
  4734 
  4735   return 0;
  4736 }
  4737 
  4738 
  4739 /*
  4740  * Function:
  4741  *
  4742  *   mp4_i32 freeVMHD(videoMediaHeaderAtom *vmhd)
  4743  *
  4744  * Description:
  4745  *
  4746  *   This function frees memory for VMHD atom.
  4747  *
  4748  * Parameters:
  4749  *
  4750  *   vmhd       VMHD atom pointer
  4751  *
  4752  * Return value:
  4753  *
  4754  *   0          Success
  4755  *   Negative   Error
  4756  *
  4757  */
  4758 mp4_i32 freeVMHD(videoMediaHeaderAtom *vmhd)
  4759 {
  4760   if (vmhd)
  4761   {
  4762     if (freeAtomHeader(vmhd->atomhdr) < 0)
  4763       return -1;
  4764 
  4765     mp4free(vmhd);
  4766   }
  4767 
  4768   return 0;
  4769 }
  4770 
  4771 
  4772 /*
  4773  * Function:
  4774  *
  4775  *   mp4_i32 freeSMHD(soundMediaHeaderAtom *smhd)
  4776  *
  4777  * Description:
  4778  *
  4779  *   This function frees memory for SMHD atom.
  4780  *
  4781  * Parameters:
  4782  *
  4783  *   smhd       SMHD atom pointer
  4784  *
  4785  * Return value:
  4786  *
  4787  *   0          Success
  4788  *   Negative   Error
  4789  *
  4790  */
  4791 mp4_i32 freeSMHD(soundMediaHeaderAtom *smhd)
  4792 {
  4793   if (smhd)
  4794   {
  4795     if (freeAtomHeader(smhd->atomhdr) < 0)
  4796       return -1;
  4797 
  4798     mp4free(smhd);
  4799   }
  4800 
  4801   return 0;
  4802 }
  4803 
  4804 
  4805 /*
  4806  * Function:
  4807  *
  4808  *   mp4_i32 freeDINF(dataInformationAtom *dinf)
  4809  *
  4810  * Description:
  4811  *
  4812  *   This function frees memory for DINF atom.
  4813  *
  4814  * Parameters:
  4815  *
  4816  *   dinf       DINF atom pointer
  4817  *
  4818  * Return value:
  4819  *
  4820  *   0          Success
  4821  *   Negative   Error
  4822  *
  4823  */
  4824 mp4_i32 freeDINF(dataInformationAtom *dinf)
  4825 {
  4826   if (dinf)
  4827   {
  4828     if (freeAtomHeader(dinf->atomhdr) < 0)
  4829       return -1;
  4830     if (freeDREF(dinf->dref) < 0)
  4831       return -1;
  4832 
  4833     mp4free(dinf);
  4834   }
  4835 
  4836   return 0;
  4837 }
  4838 
  4839 
  4840 /*
  4841  * Function:
  4842  *
  4843  *   mp4_i32 freeDREF(dataReferenceAtom *dref)
  4844  *
  4845  * Description:
  4846  *
  4847  *   This function frees memory for DREF atom.
  4848  *
  4849  * Parameters:
  4850  *
  4851  *   dref       DREF atom pointer
  4852  *
  4853  * Return value:
  4854  *
  4855  *   0          Success
  4856  *   Negative   Error
  4857  *
  4858  */
  4859 mp4_i32 freeDREF(dataReferenceAtom *dref)
  4860 {
  4861   if (dref)
  4862   {
  4863     if (freeAtomHeader(dref->atomhdr) < 0)
  4864       return -1;
  4865     if (freeURL(dref->url) < 0)
  4866       return -1;
  4867     if (freeURN(dref->urn) < 0)
  4868       return -1;
  4869 
  4870     mp4free(dref);
  4871   }
  4872 
  4873   return 0;
  4874 }
  4875 
  4876 
  4877 /*
  4878  * Function:
  4879  *
  4880  *   mp4_i32 freeURL(dataEntryURLAtom *url)
  4881  *
  4882  * Description:
  4883  *
  4884  *   This function frees memory for URL atom.
  4885  *
  4886  * Parameters:
  4887  *
  4888  *   url        URL atom pointer
  4889  *
  4890  * Return value:
  4891  *
  4892  *   0          Success
  4893  *   Negative   Error
  4894  *
  4895  */
  4896 mp4_i32 freeURL(dataEntryURLAtom *url)
  4897 {
  4898   if (url)
  4899   {
  4900     if (freeAtomHeader(url->atomhdr) < 0)
  4901       return -1;
  4902 
  4903     mp4free(url);
  4904   }
  4905 
  4906   return 0;
  4907 }
  4908 
  4909 
  4910 /*
  4911  * Function:
  4912  *
  4913  *   mp4_i32 freeURN(dataEntryURNAtom *urn)
  4914  *
  4915  * Description:
  4916  *
  4917  *   This function frees memory for URN atom.
  4918  *
  4919  * Parameters:
  4920  *
  4921  *   urn        URN atom pointer
  4922  *
  4923  * Return value:
  4924  *
  4925  *   0          Success
  4926  *   Negative   Error
  4927  *
  4928  */
  4929 mp4_i32 freeURN(dataEntryURNAtom *urn)
  4930 {
  4931   if (urn)
  4932   {
  4933     if (freeAtomHeader(urn->atomhdr) < 0)
  4934       return -1;
  4935 
  4936     mp4free(urn);
  4937   }
  4938 
  4939   return 0;
  4940 }
  4941 
  4942 
  4943 /*
  4944  * Function:
  4945  *
  4946  *   mp4_i32 freeSTBL(sampleTableAtom *stbl)
  4947  *
  4948  * Description:
  4949  *
  4950  *   This function frees memory for STBL atom.
  4951  *
  4952  * Parameters:
  4953  *
  4954  *   stbl       STBL atom pointer
  4955  *
  4956  * Return value:
  4957  *
  4958  *   0          Success
  4959  *   Negative   Error
  4960  *
  4961  */
  4962 mp4_i32 freeSTBL(sampleTableAtom *stbl)
  4963 {
  4964   if (stbl)
  4965   {
  4966     if (freeAtomHeader(stbl->atomhdr) < 0)
  4967       return -1;
  4968     if (freeSTTS(stbl->stts) < 0)
  4969       return -1;
  4970     if (freeCTTS(stbl->ctts) < 0)
  4971       return -1;
  4972     if (freeSTSD(stbl->stsd) < 0)
  4973       return -1;
  4974     if (freeSTSZ(stbl->stsz) < 0)
  4975       return -1;
  4976     if (freeSTSC(stbl->stsc) < 0)
  4977       return -1;
  4978     if (stbl->is32BitOffsets)
  4979     {
  4980     
  4981       if (freeSTCO(stbl->stco) < 0)
  4982         return -1;
  4983     }
  4984     else
  4985     {
  4986     
  4987       if (freeSTCO64(stbl->stco64) < 0)
  4988         return -1;
  4989     }
  4990     if (freeSTSS(stbl->stss) < 0)
  4991       return -1;
  4992     if (freeSTSH(stbl->stsh) < 0)
  4993       return -1;
  4994     if (freeSDTP(stbl->sdtp) < 0)
  4995       return -1;
  4996 
  4997     mp4free(stbl);
  4998   }
  4999 
  5000   return 0;
  5001 }
  5002 
  5003 
  5004 /*
  5005  * Function:
  5006  *
  5007  *   mp4_i32 freeSTTS(timeToSampleAtom *stts)
  5008  *
  5009  * Description:
  5010  *
  5011  *   This function frees memory for STTS atom.
  5012  *
  5013  * Parameters:
  5014  *
  5015  *   stts       STTS atom pointer
  5016  *
  5017  * Return value:
  5018  *
  5019  *   0          Success
  5020  *   Negative   Error
  5021  *
  5022  */
  5023 mp4_i32 freeSTTS(timeToSampleAtom *stts)
  5024 {
  5025   if (stts)
  5026   {
  5027     if (freeAtomHeader(stts->atomhdr) < 0)
  5028       return -1;
  5029     if (stts->sampleCount)
  5030       mp4free(stts->sampleCount);
  5031     if (stts->sampleDelta)
  5032       mp4free(stts->sampleDelta);
  5033 
  5034     mp4free(stts);
  5035   }
  5036 
  5037   return 0;
  5038 }
  5039 
  5040 
  5041 /*
  5042  * Function:
  5043  *
  5044  *   mp4_i32 freeCTTS(compositionTimeToSampleAtom *ctts)
  5045  *
  5046  * Description:
  5047  *
  5048  *   This function frees memory for CTTS atom.
  5049  *
  5050  * Parameters:
  5051  *
  5052  *   ctts       CTTS atom pointer
  5053  *
  5054  * Return value:
  5055  *
  5056  *   0          Success
  5057  *   Negative   Error
  5058  *
  5059  */
  5060 mp4_i32 freeCTTS(compositionTimeToSampleAtom *ctts)
  5061 {
  5062   if (ctts)
  5063   {
  5064     if (freeAtomHeader(ctts->atomhdr) < 0)
  5065       return -1;
  5066     if (ctts->sampleCount)
  5067       mp4free(ctts->sampleCount);
  5068     if (ctts->sampleOffset)
  5069       mp4free(ctts->sampleOffset);
  5070 
  5071     mp4free(ctts);
  5072   }
  5073 
  5074   return 0;
  5075 }
  5076 
  5077 
  5078 /*
  5079  * Function:
  5080  *
  5081  *   mp4_i32 freeSTSD(sampleDescriptionAtom *stsd)
  5082  *
  5083  * Description:
  5084  *
  5085  *   This function frees memory for STSD atom.
  5086  *
  5087  * Parameters:
  5088  *
  5089  *   stsd       STSD atom pointer
  5090  *
  5091  * Return value:
  5092  *
  5093  *   0          Success
  5094  *   Negative   Error
  5095  *
  5096  */
  5097 mp4_i32 freeSTSD(sampleDescriptionAtom *stsd)
  5098 {
  5099   mp4_u32 sampleentrycount = 0;
  5100   mp4_u32 entryindex;
  5101   
  5102   if (stsd)
  5103   {
  5104 	sampleentrycount = stsd->entryCount;
  5105 
  5106     if (freeAtomHeader(stsd->atomhdr) < 0)
  5107       return -1;
  5108 	for (entryindex = 0; entryindex < sampleentrycount; entryindex++)
  5109 	{
  5110 		if (freeMP4V(stsd->mp4v[entryindex]) < 0)
  5111 		  return -1;
  5112 		if (freeMP4A(stsd->mp4a[entryindex]) < 0)
  5113 		  return -1;
  5114 		if (freeMP4S(stsd->mp4s[entryindex]) < 0)
  5115 		  return -1;
  5116 		if (freeS263(stsd->s263[entryindex]) < 0)
  5117 		  return -1;
  5118 		if (freeSAMR(stsd->samr[entryindex]) < 0)
  5119 		  return -1;
  5120 		if (freeSAWB(stsd->sawb[entryindex]) < 0)
  5121 		  return -1;
  5122 		if (freeAVC1(stsd->avc1[entryindex]) < 0)
  5123 			return -1;
  5124         if (freeSQCP(stsd->sqcp[entryindex]) < 0)
  5125           return -1;
  5126 	}
  5127     mp4free(stsd);
  5128   }
  5129 
  5130   return 0;
  5131 }
  5132 
  5133 
  5134 /*
  5135  * Function:
  5136  *
  5137  *   mp4_i32 freeMP4V(visualSampleEntry *mp4v)
  5138  *
  5139  * Description:
  5140  *
  5141  *   This function frees memory for MP4V atom.
  5142  *
  5143  * Parameters:
  5144  *
  5145  *   mp4v       MP4V atom pointer
  5146  *
  5147  * Return value:
  5148  *
  5149  *   0          Success
  5150  *   Negative   Error
  5151  *
  5152  */
  5153 mp4_i32 freeMP4V(visualSampleEntry *mp4v)
  5154 {
  5155   if (mp4v)
  5156   {
  5157     if (freeAtomHeader(mp4v->atomhdr) < 0)
  5158       return -1;
  5159     if (freeESD(mp4v->esd) < 0)
  5160       return -1;
  5161 
  5162     mp4free(mp4v);
  5163   }
  5164 
  5165   return 0;
  5166 }
  5167 
  5168 
  5169 /*
  5170  * Function:
  5171  *
  5172  *   mp4_i32 freeESD(ESDAtom *esd)
  5173  *
  5174  * Description:
  5175  *
  5176  *   This function frees memory for ESD atom.
  5177  *
  5178  * Parameters:
  5179  *
  5180  *   esd        ESD atom pointer
  5181  *
  5182  * Return value:
  5183  *
  5184  *   0          Success
  5185  *   Negative   Error
  5186  *
  5187  */
  5188 mp4_i32 freeESD(ESDAtom *esd)
  5189 {
  5190   if (esd)
  5191   {
  5192     if (freeAtomHeader(esd->atomhdr) < 0)
  5193       return -1;
  5194     if (esd->URLString)
  5195       mp4free(esd->URLString);
  5196     if (esd->decSpecificInfo)
  5197       mp4free(esd->decSpecificInfo);
  5198 
  5199     mp4free(esd);
  5200   }
  5201 
  5202   return 0;
  5203 }
  5204 
  5205 
  5206 /*
  5207  * Function:
  5208  *
  5209  *   mp4_i32 freeMP4A(audioSampleEntry *mp4a)
  5210  *
  5211  * Description:
  5212  *
  5213  *   This function frees memory for MP4A atom.
  5214  *
  5215  * Parameters:
  5216  *
  5217  *   mp4a       MP4A atom pointer
  5218  *
  5219  * Return value:
  5220  *
  5221  *   0          Success
  5222  *   Negative   Error
  5223  *
  5224  */
  5225 mp4_i32 freeMP4A(audioSampleEntry *mp4a)
  5226 {
  5227   if (mp4a)
  5228   {
  5229     if (freeAtomHeader(mp4a->atomhdr) < 0)
  5230       return -1;
  5231     if (freeESD(mp4a->esd) < 0)
  5232       return -1;
  5233 
  5234     mp4free(mp4a);
  5235   }
  5236 
  5237   return 0;
  5238 }
  5239 
  5240 
  5241 /*
  5242  * Function:
  5243  *
  5244  *   mp4_i32 freeMP4S(mpegSampleEntry *mp4s)
  5245  *
  5246  * Description:
  5247  *
  5248  *   This function frees memory for MP4S atom.
  5249  *
  5250  * Parameters:
  5251  *
  5252  *   mp4s       MP4S atom pointer
  5253  *
  5254  * Return value:
  5255  *
  5256  *   0          Success
  5257  *   Negative   Error
  5258  *
  5259  */
  5260 mp4_i32 freeMP4S(mpegSampleEntry *mp4s)
  5261 {
  5262   if (mp4s)
  5263   {
  5264     if (freeAtomHeader(mp4s->atomhdr) < 0)
  5265       return -1;
  5266     if (freeESD(mp4s->esd) < 0)
  5267       return -1;
  5268 
  5269     mp4free(mp4s);
  5270   }
  5271 
  5272   return 0;
  5273 }
  5274 
  5275 
  5276 /*
  5277  * Function:
  5278  *
  5279  *   mp4_i32 freeS263(h263SampleEntry *s263)
  5280  *
  5281  * Description:
  5282  *
  5283  *   This function frees memory for S263 atom.
  5284  *
  5285  * Parameters:
  5286  *
  5287  *   s263       S263 atom pointer
  5288  *
  5289  * Return value:
  5290  *
  5291  *   0          Success
  5292  *   Negative   Error
  5293  *
  5294  */
  5295 mp4_i32 freeS263(h263SampleEntry *s263)
  5296 {
  5297   if (s263)
  5298   {
  5299     if (freeAtomHeader(s263->atomhdr) < 0)
  5300       return -1;
  5301     if (freeD263(s263->d263) < 0)
  5302       return -1;
  5303 
  5304     mp4free(s263);
  5305   }
  5306 
  5307   return 0;
  5308 }
  5309 
  5310 
  5311 /*
  5312  * Function:
  5313  *
  5314  *   mp4_i32 freeD263(h263SpecificAtom *d263)
  5315  *
  5316  * Description:
  5317  *
  5318  *   This function frees memory for D263 atom.
  5319  *
  5320  * Parameters:
  5321  *
  5322  *   d263       D263 atom pointer
  5323  *
  5324  * Return value:
  5325  *
  5326  *   0          Success
  5327  *   Negative   Error
  5328  *
  5329  */
  5330 mp4_i32 freeD263(h263SpecificAtom *d263)
  5331 {
  5332   if (d263)
  5333   {
  5334     if (freeAtomHeader(d263->atomhdr) < 0)
  5335       return -1;
  5336     if (freeBITR(d263->bitr) < 0)
  5337       return -1;
  5338 
  5339     mp4free(d263);
  5340   }
  5341 
  5342   return 0;
  5343 }
  5344 
  5345 
  5346 /*
  5347  * Function:
  5348  *
  5349  *   mp4_i32 freeBITR(BitrateAtom *bitr)
  5350  *
  5351  * Description:
  5352  *
  5353  *   This function frees memory for BITR atom.
  5354  *
  5355  * Parameters:
  5356  *
  5357  *   bitr       BITR atom pointer
  5358  *
  5359  * Return value:
  5360  *
  5361  *   0          Success
  5362  *   Negative   Error
  5363  *
  5364  */
  5365 mp4_i32 freeBITR(bitrateAtom *bitr)
  5366 {
  5367   if (bitr)
  5368   {
  5369     if (freeAtomHeader(bitr->atomhdr) < 0)
  5370       return -1;
  5371 
  5372     mp4free(bitr);
  5373   }
  5374 
  5375   return 0;
  5376 }
  5377 
  5378 
  5379 /*
  5380  * Function:
  5381  *
  5382  *   mp4_i32 freeSAMR(amrSampleEntry *samr)
  5383  *
  5384  * Description:
  5385  *
  5386  *   This function frees memory for SAMR atom.
  5387  *
  5388  * Parameters:
  5389  *
  5390  *   samr       SAMR atom pointer
  5391  *
  5392  * Return value:
  5393  *
  5394  *   0          Success
  5395  *   Negative   Error
  5396  *
  5397  */
  5398 mp4_i32 freeSAMR(amrSampleEntry *samr)
  5399 {
  5400   if (samr)
  5401   {
  5402     if (freeAtomHeader(samr->atomhdr) < 0)
  5403       return -1;
  5404     if (freeDAMR(samr->damr) < 0)
  5405       return -1;
  5406 
  5407     mp4free(samr);
  5408   }
  5409 
  5410   return 0;
  5411 }
  5412 
  5413 
  5414 /*
  5415  * Function:
  5416  *
  5417  *   mp4_i32 freeSAWB(amrSampleEntry *sawb)
  5418  *
  5419  * Description:
  5420  *
  5421  *   This function frees memory for SAWB atom.
  5422  *
  5423  * Parameters:
  5424  *
  5425  *   sawb       SAWB atom pointer
  5426  *
  5427  * Return value:
  5428  *
  5429  *   0          Success
  5430  *   Negative   Error
  5431  *
  5432  */
  5433 mp4_i32 freeSAWB(amrSampleEntry *sawb)
  5434 {
  5435   if (sawb)
  5436   {
  5437     if (freeAtomHeader(sawb->atomhdr) < 0)
  5438       return -1;
  5439     if (freeDAMR(sawb->damr) < 0)
  5440       return -1;
  5441 
  5442     mp4free(sawb);
  5443   }
  5444 
  5445   return 0;
  5446 }
  5447 
  5448 
  5449 /*
  5450  * Function:
  5451  *
  5452  *   mp4_i32 freeDAMR(amrDecSpecStruc *damr)
  5453  *
  5454  * Description:
  5455  *
  5456  *   This function frees memory for DAMR atom.
  5457  *
  5458  * Parameters:
  5459  *
  5460  *   damr       DAMR atom pointer
  5461  *
  5462  * Return value:
  5463  *
  5464  *   0          Success
  5465  *   Negative   Error
  5466  *
  5467  */
  5468 mp4_i32 freeDAMR(amrDecSpecStruc *damr)
  5469 {
  5470   if (damr)
  5471   {
  5472     if (freeAtomHeader(damr->atomhdr) < 0)
  5473       return -1;
  5474 
  5475     mp4free(damr);
  5476   }
  5477 
  5478   return 0;
  5479 }
  5480 
  5481 
  5482 /*
  5483  * Function:
  5484  *
  5485  *   mp4_i32 freeSTSZ(sampleSizeAtom *stsz)
  5486  *
  5487  * Description:
  5488  *
  5489  *   This function frees memory for STSZ atom.
  5490  *
  5491  * Parameters:
  5492  *
  5493  *   stsz       STSZ atom pointer
  5494  *
  5495  * Return value:
  5496  *
  5497  *   0          Success
  5498  *   Negative   Error
  5499  *
  5500  */
  5501 mp4_i32 freeSTSZ(sampleSizeAtom *stsz)
  5502 {
  5503   if (stsz)
  5504   {
  5505     if (freeAtomHeader(stsz->atomhdr) < 0)
  5506       return -1;
  5507     if (stsz->entrySize)
  5508       mp4free(stsz->entrySize);
  5509 
  5510     mp4free(stsz);
  5511   }
  5512 
  5513   return 0;
  5514 }
  5515 
  5516 
  5517 /*
  5518  * Function:
  5519  *
  5520  *   mp4_i32 freeSTSC(sampleToChunkAtom *stsc)
  5521  *
  5522  * Description:
  5523  *
  5524  *   This function frees memory for STSC atom.
  5525  *
  5526  * Parameters:
  5527  *
  5528  *   stsc       STSC atom pointer
  5529  *
  5530  * Return value:
  5531  *
  5532  *   0          Success
  5533  *   Negative   Error
  5534  *
  5535  */
  5536 mp4_i32 freeSTSC(sampleToChunkAtom *stsc)
  5537 {
  5538   if (stsc)
  5539   {
  5540     if (freeAtomHeader(stsc->atomhdr) < 0)
  5541       return -1;
  5542     if (stsc->firstChunk)
  5543       mp4free(stsc->firstChunk);
  5544     if (stsc->samplesPerChunk)
  5545       mp4free(stsc->samplesPerChunk);
  5546     if (stsc->sampleDescriptionIndex)
  5547       mp4free(stsc->sampleDescriptionIndex);
  5548 
  5549     mp4free(stsc);
  5550   }
  5551 
  5552   return 0;
  5553 }
  5554 
  5555 
  5556 /*
  5557  * Function:
  5558  *
  5559  *   mp4_i32 freeSTCO(chunkOffsetAtom *stco)
  5560  *
  5561  * Description:
  5562  *
  5563  *   This function frees memory for STCO atom.
  5564  *
  5565  * Parameters:
  5566  *
  5567  *   stco       STCO atom pointer
  5568  *
  5569  * Return value:
  5570  *
  5571  *   0          Success
  5572  *   Negative   Error
  5573  *
  5574  */
  5575 mp4_i32 freeSTCO(chunkOffsetAtom *stco)
  5576 {
  5577   if (stco)
  5578   {
  5579     if (freeAtomHeader(stco->atomhdr) < 0)
  5580       return -1;
  5581     if (stco->chunkOffset)
  5582       mp4free(stco->chunkOffset);
  5583 
  5584     mp4free(stco);
  5585   }
  5586 
  5587   return 0;
  5588 }
  5589 
  5590 /*
  5591  * Function:
  5592  *
  5593  *   mp4_i32 freeSTCO64(chunkOffset64Atom *stco64)
  5594  *
  5595  * Description:
  5596  *
  5597  *   This function frees memory for STCO64 atom.
  5598  *
  5599  * Parameters:
  5600  *
  5601  *   stco64       STCO64 atom pointer
  5602  *
  5603  * Return value:
  5604  *
  5605  *   0          Success
  5606  *   Negative   Error
  5607  *
  5608  */
  5609 mp4_i32 freeSTCO64(chunkOffset64Atom *stco64)
  5610 {
  5611   if (stco64)
  5612   {
  5613     if (freeAtomHeader(stco64->atomhdr) < 0)
  5614       return -1;
  5615     if (stco64->chunkOffset)
  5616       mp4free(stco64->chunkOffset);
  5617 
  5618     mp4free(stco64);
  5619   }
  5620 
  5621   return 0;
  5622 }
  5623 
  5624 
  5625 /*
  5626  * Function:
  5627  *
  5628  *   mp4_i32 freeSTSS(syncSampleAtom *stss)
  5629  *
  5630  * Description:
  5631  *
  5632  *   This function frees memory for STSS atom.
  5633  *
  5634  * Parameters:
  5635  *
  5636  *   stss       STSS atom pointer
  5637  *
  5638  * Return value:
  5639  *
  5640  *   0          Success
  5641  *   Negative   Error
  5642  *
  5643  */
  5644 mp4_i32 freeSTSS(syncSampleAtom *stss)
  5645 {
  5646   if (stss)
  5647   {
  5648     if (freeAtomHeader(stss->atomhdr) < 0)
  5649       return -1;
  5650     if (stss->sampleNumber)
  5651       mp4free(stss->sampleNumber);
  5652 
  5653     mp4free(stss);
  5654   }
  5655 
  5656   return 0;
  5657 }
  5658 
  5659 
  5660 /*
  5661  * Function:
  5662  *
  5663  *   mp4_i32 freeSTSH(shadowSyncSampleAtom *stsh)
  5664  *
  5665  * Description:
  5666  *
  5667  *   This function frees memory for STSH atom.
  5668  *
  5669  * Parameters:
  5670  *
  5671  *   stsh       STSH atom pointer
  5672  *
  5673  * Return value:
  5674  *
  5675  *   0          Success
  5676  *   Negative   Error
  5677  *
  5678  */
  5679 mp4_i32 freeSTSH(shadowSyncSampleAtom *stsh)
  5680 {
  5681   if (stsh)
  5682   {
  5683     if (freeAtomHeader(stsh->atomhdr) < 0)
  5684       return -1;
  5685 
  5686     mp4free(stsh);
  5687   }
  5688 
  5689   return 0;
  5690 }
  5691 
  5692 
  5693 /*
  5694  * Function:
  5695  *
  5696  *   mp4_i32 freeSDTP(sampleDependencyAtom *sdtp)
  5697  *
  5698  * Description:
  5699  *
  5700  *   This function frees memory for SDTP atom.
  5701  *
  5702  * Parameters:
  5703  *
  5704  *   sdtp       SDTP atom pointer
  5705  *
  5706  * Return value:
  5707  *
  5708  *   0          Success
  5709  *   Negative   Error
  5710  *
  5711  */
  5712 mp4_i32 freeSDTP(sampleDependencyAtom *sdtp)
  5713 	{
  5714 	if (sdtp)
  5715 		{
  5716 		if (freeAtomHeader(sdtp->atomhdr) < 0)
  5717 			{
  5718 			return -1;
  5719 			}
  5720 
  5721 		if (sdtp->dep)
  5722 			{
  5723 			mp4free(sdtp->dep);
  5724 			}		
  5725     
  5726 		mp4free(sdtp);
  5727 		}
  5728 
  5729   	return 0;
  5730 	}
  5731 
  5732 /*
  5733  * Function:
  5734  *
  5735  *   mp4_i32 freeIODS(objectDescriptorAtom *iods)
  5736  *
  5737  * Description:
  5738  *
  5739  *   This function frees memory for IODS atom.
  5740  *
  5741  * Parameters:
  5742  *
  5743  *   iods       IODS atom pointer
  5744  *
  5745  * Return value:
  5746  *
  5747  *   0          Success
  5748  *   Negative   Error
  5749  *
  5750  */
  5751 mp4_i32 freeIODS(objectDescriptorAtom *iods)
  5752 {
  5753   if (iods)
  5754   {
  5755     if (freeAtomHeader(iods->atomhdr) < 0)
  5756       return -1;
  5757 
  5758     mp4free(iods);
  5759   }
  5760 
  5761   return 0;
  5762 }
  5763 
  5764 
  5765 /*
  5766  * Function:
  5767  *
  5768  *   mp4_i32 readUDTA(MP4HandleImp handle,
  5769  *                    userDataAtom *udta)
  5770  *
  5771  * Description:
  5772  *
  5773  *   This function parses one UDTA atom.
  5774  *
  5775  * Parameters:
  5776  *
  5777  *   handle             MP4 library handle
  5778  *   udta               UDTA pointer
  5779  *
  5780  * Return value:
  5781  *
  5782  *   Negative integer   Error
  5783  *   >= 0               Success. Value tells how many bytes were read.
  5784  *
  5785  */
  5786 mp4_i32 readUDTA(MP4HandleImp handle, userDataAtom *udta)
  5787 {
  5788   mp4_i32 bytesread;
  5789   mp4_i32 totalbytesread = 0;
  5790 
  5791   if ((udta->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  5792     return -100;
  5793 
  5794   bytesread = readAtomHeader(handle, udta->atomhdr);
  5795   if (bytesread < 0)
  5796     return -1;
  5797   totalbytesread += bytesread;
  5798 
  5799   if (udta->atomhdr->type != ATOMTYPE_UDTA)
  5800     return -1;
  5801 
  5802   if ( handle->file )
  5803       {
  5804       udta->atomcontentloc = handle->diskReadBufStart + handle->diskReadBufPos;
  5805       }
  5806   else
  5807       {
  5808       udta->atomcontentloc = handle->absPosition;
  5809       }
  5810 
  5811   if ( udta->atomhdr->size == 1 )
  5812       {
  5813       udta->atomcontentsize = I64INT(udta->atomhdr->largeSize) - (TInt)totalbytesread;
  5814       }
  5815   else
  5816       {
  5817       udta->atomcontentsize = (TInt)(udta->atomhdr->size - totalbytesread);
  5818       }
  5819 
  5820   if ( handle->file )
  5821   {
  5822   	if ( seekFile(handle, udta->atomhdr->size - totalbytesread) < 0 )
  5823   	{
  5824   	   return -1;	
  5825   	}
  5826   	else
  5827   	{
  5828   	   return udta->atomhdr->size;	
  5829   	}
  5830   }
  5831   else
  5832   {
  5833 	  bytesread = discardData(handle, udta->atomhdr->size - totalbytesread);
  5834 	  if (bytesread < 0)
  5835 	    return -1;
  5836 	  totalbytesread += bytesread;
  5837   }
  5838   return totalbytesread;
  5839 }
  5840 
  5841 /*
  5842  * Function:
  5843  *
  5844  *   mp4_i32 freeUDTA(userDataAtom *udta)
  5845  *
  5846  * Description:
  5847  *
  5848  *   This function frees memory for UDTA atom.
  5849  *
  5850  * Parameters:
  5851  *
  5852  *   udta       UDTA atom pointer
  5853  *
  5854  * Return value:
  5855  *
  5856  *   0          Success
  5857  *   Negative   Error
  5858  *
  5859  */
  5860 mp4_i32 freeUDTA(userDataAtom *udta)
  5861 {
  5862   if (udta)
  5863   {
  5864     if (freeAtomHeader(udta->atomhdr) < 0)
  5865       return -1;
  5866     mp4free(udta);
  5867   }
  5868 
  5869   return 0;
  5870 }
  5871 
  5872 
  5873 /*
  5874  * Function:
  5875  *
  5876  *   mp4_i32 determineVideoLength(MP4HandleImp handle,
  5877  *                                mp4_u32 *videolength)
  5878  *
  5879  * Description:
  5880  *
  5881  *   This function determines the length of video in milliseconds.
  5882  *
  5883  * Parameters:
  5884  *
  5885  *   handle       MP4 library handle
  5886  *   videolength  Video length is returned here
  5887  *
  5888  * Return value:
  5889  *
  5890  *   0            Success
  5891  *   Negative     Error
  5892  *
  5893  */
  5894 mp4_i32 determineVideoLength(MP4HandleImp handle, mp4_u32 *videolength)
  5895 {
  5896   if (!handle->moov)
  5897     return -1;
  5898 
  5899   if (!handle->moov->mvhd)
  5900     return -1;
  5901 
  5902   if (!handle->moov->trakVideo)
  5903     return -1;
  5904 
  5905   if (!handle->moov->trakVideo->tkhd)
  5906     return -1;
  5907 
  5908   /* Is timescale set? */
  5909   if (handle->moov->mvhd->timeScale == 0)
  5910     return -1;
  5911 
  5912   *videolength = (mp4_u32)(((mp4_double)handle->moov->trakVideo->tkhd->duration / (mp4_double)handle->moov->mvhd->timeScale) * (mp4_double)1000);
  5913 
  5914   return 0;
  5915 }
  5916 
  5917 
  5918 /*
  5919  * Function:
  5920  *
  5921  *   mp4_i32 determineFrameRate(MP4HandleImp handle,
  5922  *                              mp4_double *framerate)
  5923  *
  5924  * Description:
  5925  *
  5926  *   This function determines the frame rate of video.
  5927  *
  5928  *   Frame rate is calculated as the average frame rate of the entire video.
  5929  *
  5930  * Parameters:
  5931  *
  5932  *   handle     MP4 library handle
  5933  *   framerate  Frame rate is returned here
  5934  *
  5935  * Return value:
  5936  *
  5937  *   0          Success
  5938  *   Negative   Error
  5939  *
  5940  */
  5941 mp4_i32 determineFrameRate(MP4HandleImp handle, mp4_double *framerate)
  5942 {
  5943   mp4_double numberofframes;
  5944   mp4_double length;
  5945 
  5946 
  5947   if (!handle)
  5948     return -1;
  5949   if (!handle->moov)
  5950     return -1;
  5951   if (!handle->moov->trakVideo)
  5952     return -1;
  5953   if (!handle->moov->trakVideo->mdia)
  5954     return -1;
  5955   if (!handle->moov->trakVideo->mdia->minf)
  5956     return -1;
  5957   if (!handle->moov->trakVideo->mdia->minf->stbl)
  5958     return -1;
  5959   if (!handle->moov->trakVideo->mdia->minf->stbl->stsz)
  5960     return -1;
  5961   if (!handle->moov->trakVideo->mdia->mdhd)
  5962     return -1;
  5963 
  5964 
  5965   	if (handle->moov->trakVideo->mdia->mdhd->timeScale == 0)
  5966     	return -1;
  5967   	
  5968   	if (handle->moov->trakVideo->mdia->mdhd->duration == 0)
  5969   		{
  5970   		*framerate = 0;
  5971   		}
  5972 	else
  5973 		{
  5974   		numberofframes = (mp4_double)handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount;
  5975   		length = (mp4_double)handle->moov->trakVideo->mdia->mdhd->duration /
  5976            		 (mp4_double)handle->moov->trakVideo->mdia->mdhd->timeScale;
  5977 
  5978   		*framerate = numberofframes / length;			
  5979 		}    
  5980 
  5981   	return 0;
  5982 	}
  5983 
  5984 
  5985 /*
  5986  * Function:
  5987  *
  5988  *   mp4_i32 determineVideoType(MP4HandleImp handle,
  5989  *                              mp4_u32 *videotype)
  5990  *
  5991  * Description:
  5992  *
  5993  *   This function determines the video type of the MP4.
  5994  *
  5995  * Parameters:
  5996  *
  5997  *   handle     MP4 library handle
  5998  *   videotype  Video type is returned here
  5999  *
  6000  * Return value:
  6001  *
  6002  *   0          Success
  6003  *   -1			Error
  6004  *	 -2			Unknown video type
  6005  *
  6006  */
  6007 mp4_i32 determineVideoType(MP4HandleImp handle, mp4_u32 *videotype)
  6008 {
  6009   *videotype = MP4_TYPE_NONE;
  6010 
  6011   if (!handle->moov)
  6012     return -1;
  6013 
  6014   if (!handle->moov->trakVideo)
  6015     return -1;
  6016 
  6017   if (!handle->moov->trakVideo->mdia)
  6018     return -1;
  6019 
  6020   if (!handle->moov->trakVideo->mdia->minf)
  6021     return -1;
  6022 
  6023   if (!handle->moov->trakVideo->mdia->minf->stbl)
  6024     return -1;
  6025 
  6026   if (!handle->moov->trakVideo->mdia->minf->stbl->stsd)
  6027     return -1;
  6028   
  6029   if (handle->moov->trakVideo->mdia->minf->stbl->stsd->entryCount == 0)
  6030     return -1;  
  6031 
  6032 /* Assume that the video type is the same for all sample entries. Just get the video type from the first one */
  6033 
  6034   if (handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0])
  6035   {
  6036     if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->esd)
  6037       return -1;
  6038 
  6039     if ((handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->esd->objectTypeIndication == 0x20) &&
  6040         ((handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->esd->stream >> 2) == 0x04))
  6041       *videotype = MP4_TYPE_MPEG4_VIDEO;
  6042   }
  6043   else
  6044   if (handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0])
  6045   {
  6046     if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->d263)
  6047       return -1;
  6048 
  6049     switch (handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->d263->h263Profile)
  6050     {
  6051     case 0:
  6052       *videotype = MP4_TYPE_H263_PROFILE_0;
  6053       break;
  6054     case 3:
  6055       *videotype = MP4_TYPE_H263_PROFILE_3;
  6056       break;
  6057     default:
  6058       break;
  6059     }
  6060   }
  6061   else
  6062    if (handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0])
  6063    {
  6064 	   if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc)
  6065 		   return -1;
  6066 
  6067 	   if (handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfigSize == 0)
  6068 		   return -1;
  6069 
  6070 	   /* AVC profile is in the second byte of the avcconfigrecord */
  6071 	   switch((mp4_u8)handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfig[1]) 
  6072 	   {
  6073 	   case 66:
  6074 		   *videotype = MP4_TYPE_AVC_PROFILE_BASELINE;
  6075 		   break;
  6076 	   case 77:
  6077 		   *videotype = MP4_TYPE_AVC_PROFILE_MAIN;
  6078 		   break;
  6079 	   case 88:
  6080 		   *videotype = MP4_TYPE_AVC_PROFILE_EXTENDED;
  6081 		   break;
  6082        case 100:
  6083           *videotype = MP4_TYPE_AVC_PROFILE_HIGH;
  6084            break;
  6085 	   default:
  6086 		   {
  6087 		   mp4_u8 constraintByte = (mp4_u8)handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfig[2];
  6088 		   if ( (constraintByte & 0x80) || (constraintByte & 0x10) )
  6089 			   {
  6090 			   *videotype = MP4_TYPE_AVC_PROFILE_BASELINE;	
  6091 			   }
  6092 		   else if (constraintByte & 0x40)
  6093 			   {
  6094 			   *videotype = MP4_TYPE_AVC_PROFILE_MAIN;	
  6095 			   }
  6096 		   else if (constraintByte & 0x20)
  6097 			   {
  6098 			   *videotype = MP4_TYPE_AVC_PROFILE_EXTENDED;
  6099 			   }
  6100 		   // NOTE: Cannot reliably determine higher profiles from
  6101 		   // the constraint flags.
  6102 		   break;	   	
  6103 		   }
  6104 	   }
  6105 	}
  6106    else
  6107        {}
  6108    /* Note: Read the AVC level and recreate the actual AVC profile and level in the future! */
  6109   if (*videotype == MP4_TYPE_NONE)
  6110     return -2;
  6111 
  6112   return 0;
  6113 }
  6114 
  6115 
  6116 /*
  6117  * Function:
  6118  *
  6119  *   mp4_i32 determineVideoResolution(MP4HandleImp handle,
  6120  *                                    mp4_u32 *videowidth,
  6121  *                                    mp4_u32 *videoheight)
  6122  *
  6123  * Description:
  6124  *
  6125  *   This function finds out the video width and height from the atom
  6126  *   structure.
  6127  *
  6128  * Parameters:
  6129  *
  6130  *   handle       MP4 library handle
  6131  *   videowidth   Video width is returned here
  6132  *   videoheight  Video height is returned here
  6133  *
  6134  * Return value:
  6135  *
  6136  *   0            Success
  6137  *   Negative     Error
  6138  *
  6139  */
  6140 mp4_i32 determineVideoResolution(MP4HandleImp handle, mp4_u32 *videowidth, mp4_u32 *videoheight)
  6141 {
  6142   mp4_u32 videotype = MP4_TYPE_NONE;
  6143 
  6144 
  6145   if (determineVideoType(handle, &videotype) < 0)
  6146     return -1;
  6147 
  6148   if (videotype == MP4_TYPE_NONE)
  6149     return -1;
  6150 
  6151   if (!handle->moov)
  6152     return -1;
  6153 
  6154   if (!handle->moov->trakVideo)
  6155     return -1;
  6156 
  6157   if (!handle->moov->trakVideo->mdia)
  6158     return -1;
  6159 
  6160   if (!handle->moov->trakVideo->mdia->minf)
  6161     return -1;
  6162 
  6163   if (!handle->moov->trakVideo->mdia->minf->stbl)
  6164     return -1;
  6165 
  6166   if (!handle->moov->trakVideo->mdia->minf->stbl->stsd)
  6167     return -1;
  6168 
  6169   if (handle->moov->trakVideo->mdia->minf->stbl->stsd->entryCount == 0)
  6170     return -1;  
  6171   
  6172 /* Assume that the video characteristics for all the video sample entries are the same. Just get them from the first one */
  6173 
  6174   if (videotype == MP4_TYPE_H263_PROFILE_0 ||
  6175       videotype == MP4_TYPE_H263_PROFILE_3)
  6176   {
  6177     if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0])
  6178       return -1;
  6179 
  6180     *videowidth  = handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->width;
  6181     *videoheight = handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->height;
  6182   }
  6183   else if (videotype == MP4_TYPE_MPEG4_VIDEO)
  6184   {
  6185     if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0])
  6186       return -1;
  6187 
  6188     *videowidth  = handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->width;
  6189     *videoheight = handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->height;
  6190   }
  6191   else if ( isAvcVideo(videotype) )
  6192   {
  6193     if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0])
  6194       return -1;
  6195 
  6196     *videowidth  = handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->width;
  6197     *videoheight = handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->height;
  6198   }
  6199   else
  6200   {
  6201   }
  6202 
  6203   return 0;
  6204 }
  6205 
  6206 
  6207 /*
  6208  * Function:
  6209  *
  6210  *   mp4_i32 determineVideoTimeScale(MP4HandleImp handle,
  6211  *                                   mp4_u32 *timescale)
  6212  *
  6213  * Description:
  6214  *
  6215  *   This function determines the timescale of video track.
  6216  *
  6217  * Parameters:
  6218  *
  6219  *   handle     MP4 library handle
  6220  *   timescale  Timescale of video track is returned here
  6221  *
  6222  * Return value:
  6223  *
  6224  *   0          Success
  6225  *   Negative   Error
  6226  *
  6227  */
  6228 mp4_i32 determineVideoTimeScale(MP4HandleImp handle, mp4_u32 *timescale)
  6229 {
  6230   if (timescale == NULL)
  6231     return 0;
  6232 
  6233   if (!handle)
  6234     return -1;
  6235   if (!handle->moov)
  6236     return -1;
  6237   if (!handle->moov->trakVideo)
  6238     return -1;
  6239   if (!handle->moov->trakVideo->mdia)
  6240     return -1;
  6241   if (!handle->moov->trakVideo->mdia->mdhd)
  6242     return -1;
  6243   if (handle->moov->trakVideo->mdia->mdhd->timeScale == 0)
  6244     return -1;
  6245 
  6246   *timescale = handle->moov->trakVideo->mdia->mdhd->timeScale;
  6247 
  6248   return 0;
  6249 }
  6250 
  6251 
  6252 /*
  6253  * Function:
  6254  *
  6255  *   mp4_i32 determineAudioLength(MP4HandleImp handle,
  6256  *                                mp4_u32 *audiolength)
  6257  *
  6258  * Description:
  6259  *
  6260  *   This function determines the length of audio in milliseconds.
  6261  *
  6262  * Parameters:
  6263  *
  6264  *   handle       MP4 library handle
  6265  *   audiolength  Audio length is returned here
  6266  *
  6267  * Return value:
  6268  *
  6269  *   0            Success
  6270  *   Negative     Error
  6271  *
  6272  */
  6273 mp4_i32 determineAudioLength(MP4HandleImp handle, mp4_u32 *audiolength)
  6274 {
  6275   if (!handle->moov)
  6276     return -1;
  6277 
  6278   if (!handle->moov->mvhd)
  6279     return -1;
  6280 
  6281   if (!handle->moov->trakAudio)
  6282     return -1;
  6283 
  6284   if (!handle->moov->trakAudio->tkhd)
  6285     return -1;
  6286 
  6287   /* Is timescale set? */
  6288   if (handle->moov->mvhd->timeScale == 0)
  6289     return -1;
  6290 
  6291   *audiolength = (mp4_u32)(((mp4_double)handle->moov->trakAudio->tkhd->duration / (mp4_double)handle->moov->mvhd->timeScale) * (mp4_double)1000);
  6292 
  6293   return 0;
  6294 }
  6295 
  6296 
  6297 /*
  6298  * Function:
  6299  *
  6300  *   mp4_i32 determineAudioType(MP4HandleImp handle,
  6301  *                              mp4_u32 *audiotype)
  6302  *
  6303  * Description:
  6304  *
  6305  *   This function determines the audio type of the MP4.
  6306  *
  6307  * Parameters:
  6308  *
  6309  *   handle     MP4 library handle
  6310  *   audiotype  Audio type is returned here
  6311  *
  6312  * Return value:
  6313  *
  6314  *   0          Success
  6315  *   -1   		Error
  6316  *   -2			Unknown audiotrack
  6317  *
  6318  */
  6319 mp4_i32 determineAudioType(MP4HandleImp handle, mp4_u32 *audiotype)
  6320 {
  6321   *audiotype = MP4_TYPE_NONE;
  6322 
  6323 
  6324   if (!handle->moov)
  6325     return -1;
  6326 
  6327   if (!handle->moov->trakAudio)
  6328     return -1;
  6329 
  6330   if (!handle->moov->trakAudio->mdia)
  6331     return -1;
  6332 
  6333   if (!handle->moov->trakAudio->mdia->minf)
  6334     return -1;
  6335 
  6336   if (!handle->moov->trakAudio->mdia->minf->stbl)
  6337     return -1;
  6338 
  6339   if (!handle->moov->trakAudio->mdia->minf->stbl->stsd)
  6340     return -1;
  6341   
  6342   if (handle->moov->trakAudio->mdia->minf->stbl->stsd->entryCount == 0)
  6343     return -1;  
  6344 
  6345 /* Assume that the audio type is the same for all sample entries. Just get the audio type from the first one */
  6346   if (handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0])
  6347   {
  6348     if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd)
  6349       return -1;
  6350 
  6351     if ((handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd->objectTypeIndication == 0x40) &&
  6352         ((handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd->stream >> 2) == 0x05))
  6353       *audiotype = MP4_TYPE_MPEG4_AUDIO;
  6354 
  6355    if ((handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd->objectTypeIndication == 0xE1) &&
  6356      ((handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd->stream >> 2) == 0x05))  
  6357    {
  6358       *audiotype = MP4_TYPE_QCELP_13K;
  6359       handle->qcelpStoredAsMPEGAudio = MP4TRUE;
  6360    }
  6361   }
  6362   else if (handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[0])
  6363     *audiotype = MP4_TYPE_AMR_NB;
  6364   else if (handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[0])
  6365     *audiotype = MP4_TYPE_AMR_WB;
  6366   else if (handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[0])
  6367   {
  6368     *audiotype = MP4_TYPE_QCELP_13K;
  6369     handle->qcelpStoredAsMPEGAudio = MP4FALSE;
  6370   }
  6371   else
  6372   {
  6373   }
  6374 
  6375   if (*audiotype == MP4_TYPE_NONE)
  6376     return -2;
  6377 
  6378   return 0;
  6379 }
  6380 
  6381 
  6382 /*
  6383  * Function:
  6384  *
  6385  *   mp4_i32 determineAudioFramesPerSample(MP4HandleImp handle,
  6386  *                                         mp4_u8 *framespersample)
  6387  *
  6388  * Description:
  6389  *
  6390  *   This function determines the number of audio frames in each sample.
  6391  *   The function works with AMR audio type only.
  6392  *
  6393  * Parameters:
  6394  *
  6395  *   handle           MP4 library handle
  6396  *   framespersample  Number of frames in each sample
  6397  *
  6398  * Return value:
  6399  *
  6400  *   0                Success
  6401  *   Negative         Error
  6402  *
  6403  */
  6404 mp4_i32 determineAudioFramesPerSample(MP4HandleImp handle, mp4_u8 *framespersample)
  6405 {
  6406   mp4_i8 sampleentryindex;
  6407   
  6408   *framespersample = 0;
  6409 
  6410 
  6411   if (!((handle->type & MP4_TYPE_AMR_NB) ||
  6412         (handle->type & MP4_TYPE_AMR_WB) ||
  6413         ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio))))
  6414   {
  6415     *framespersample = 1;
  6416 
  6417     return 0;
  6418   }
  6419 
  6420 
  6421   if (!handle->moov)
  6422     return -1;
  6423 
  6424   if (!handle->moov->trakAudio)
  6425     return -1;
  6426 
  6427   if (!handle->moov->trakAudio->mdia)
  6428     return -1;
  6429 
  6430   if (!handle->moov->trakAudio->mdia->minf)
  6431     return -1;
  6432 
  6433   if (!handle->moov->trakAudio->mdia->minf->stbl)
  6434     return -1;
  6435 
  6436   if (!handle->moov->trakAudio->mdia->minf->stbl->stsd)
  6437     return -1;
  6438 
  6439   if (handle->type & MP4_TYPE_AMR_NB)
  6440   {
  6441 /* Now, framespersample returns the maximum frames_per_sample listed in the AMR sample entries*/
  6442 	for (sampleentryindex = 0; (mp4_u8) sampleentryindex < handle->moov->trakAudio->mdia->minf->stbl->stsd->entryCount; sampleentryindex++)
  6443 	{
  6444 		if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[sampleentryindex])
  6445 		  return -1;
  6446 
  6447 		if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[sampleentryindex]->damr)
  6448 		  return -1;
  6449 
  6450 		if (*framespersample < handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[sampleentryindex]->damr->framesPerSample)
  6451 			*framespersample = handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[sampleentryindex]->damr->framesPerSample;
  6452 	}
  6453   }
  6454   else if (handle->type & MP4_TYPE_AMR_WB)
  6455   {
  6456 /* Now, framespersample returns the maximum frames_per_sample listed in the AMR sample entries*/
  6457 	for (sampleentryindex = 0; (mp4_u8)sampleentryindex < handle->moov->trakAudio->mdia->minf->stbl->stsd->entryCount; sampleentryindex++)
  6458 	{
  6459 		if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[sampleentryindex])
  6460 		  return -1;
  6461 
  6462 		if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[sampleentryindex]->damr)
  6463 		  return -1;
  6464 
  6465 		if (*framespersample < handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[sampleentryindex]->damr->framesPerSample)
  6466  		  *framespersample = handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[sampleentryindex]->damr->framesPerSample;
  6467 	}
  6468   }
  6469   else if ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio))
  6470   {
  6471 /* Now, framespersample returns the maximum frames_per_sample listed in the QCELP-13K sample entries*/
  6472 	for (sampleentryindex = 0; (mp4_u8)sampleentryindex < handle->moov->trakAudio->mdia->minf->stbl->stsd->entryCount; sampleentryindex++)
  6473 	{
  6474 		if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[sampleentryindex])
  6475 		  return -1;
  6476 
  6477 		if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[sampleentryindex]->dqcp)
  6478 		  return -1;
  6479 
  6480 		if (*framespersample < handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[sampleentryindex]->dqcp->framesPerSample)
  6481 		  *framespersample = handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[sampleentryindex]->dqcp->framesPerSample;
  6482 	}
  6483   }
  6484   else
  6485   {
  6486   }
  6487 
  6488   return 0;
  6489 }
  6490 
  6491 
  6492 /*
  6493  * Function:
  6494  *
  6495  *   mp4_i32 determineAudioTimeScale(MP4HandleImp handle,
  6496  *                                   mp4_u32 *timescale)
  6497  *
  6498  * Description:
  6499  *
  6500  *   This function determines the timescale of audio track.
  6501  *
  6502  * Parameters:
  6503  *
  6504  *   handle     MP4 library handle
  6505  *   timescale  Timescale of audio track is returned here
  6506  *
  6507  * Return value:
  6508  *
  6509  *   0          Success
  6510  *   Negative   Error
  6511  *
  6512  */
  6513 mp4_i32 determineAudioTimeScale(MP4HandleImp handle, mp4_u32 *timescale)
  6514 {
  6515   if (timescale == NULL)
  6516     return 0;
  6517 
  6518   if (!handle)
  6519     return -1;
  6520   if (!handle->moov)
  6521     return -1;
  6522   if (!handle->moov->trakAudio)
  6523     return -1;
  6524   if (!handle->moov->trakAudio->mdia)
  6525     return -1;
  6526   if (!handle->moov->trakAudio->mdia->mdhd)
  6527     return -1;
  6528 
  6529 
  6530   if (handle->moov->trakAudio->mdia->mdhd->timeScale == 0)
  6531     return -1;
  6532 
  6533   *timescale = handle->moov->trakAudio->mdia->mdhd->timeScale;
  6534 
  6535   return 0;
  6536 }
  6537 
  6538 
  6539 /*
  6540  * Function:
  6541  *
  6542  *   mp4_i32 determineAudioAverageBitRate(MP4HandleImp handle,
  6543  *                                        mp4_u32 *averagebitrate)
  6544  *
  6545  * Description:
  6546  *
  6547  *   This function determines the average bitrate of the audio in bits per
  6548  *   second.
  6549  *
  6550  *   The average is calculated so that the audio data length is divided by
  6551  *   the length of the  audio track.
  6552  *
  6553  * Parameters:
  6554  *
  6555  *   handle                MP4 library handle
  6556  *   averagebitrate        Result is returned here
  6557  *
  6558  * Return value:
  6559  *
  6560  *   0           Success
  6561  *   Negative    Error
  6562  *
  6563  */
  6564 mp4_i32 determineAudioAverageBitRate(MP4HandleImp handle, mp4_u32 *averagebitrate)
  6565 	{
  6566 	mp4_u32 audiosize = 0;
  6567 
  6568   	if (!handle->moov)
  6569   		{
  6570   		return -1;	
  6571   		}
  6572     	
  6573   	if (handle->moov->trakAudio)
  6574   		{
  6575 		if (!handle->moov->trakAudio->mdia)
  6576 			{
  6577 			return -1;		
  6578 			}
  6579 					
  6580 		if (!handle->moov->trakAudio->mdia->minf)
  6581 			{
  6582 			return -1;	
  6583 			}
  6584 		
  6585 		if (!handle->moov->trakAudio->mdia->minf->stbl)
  6586 			{
  6587 			return -1;				
  6588 			}
  6589 
  6590 		if (!handle->moov->trakAudio->mdia->minf->stbl->stsz)
  6591 			{
  6592 			return -1;				
  6593 			}
  6594 
  6595 		if (handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleSize != 0)
  6596 			{
  6597 			audiosize += (handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleCount *
  6598 	                   	 handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleSize);			
  6599 			}
  6600 	    else
  6601 	    	{
  6602 	      	mp4_u32 i;
  6603 	      	for (i = 0; i < handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleCount; i++)
  6604 	      		{
  6605 	        	audiosize += handle->moov->trakAudio->mdia->minf->stbl->stsz->entrySize[i];      			
  6606 	      		}
  6607 	    	}
  6608 	  	}
  6609 	else
  6610 		{
  6611 		return -1;  		
  6612 		}
  6613 
  6614   	if (!handle->moov->trakAudio->mdia->mdhd)
  6615   		{
  6616     	return -1;  			
  6617   		}
  6618   	
  6619   	if (!handle->moov->trakAudio->mdia->mdhd->timeScale)
  6620   		{
  6621 		return -1;  			
  6622   		}
  6623 
  6624   	if (handle->moov->trakAudio->mdia->mdhd->duration == 0)
  6625   		{
  6626   		*averagebitrate = 0;
  6627   		}
  6628 	else
  6629 		{
  6630 		*averagebitrate = (mp4_u32)((mp4_double)8 *
  6631 		                  (mp4_double)audiosize /
  6632 		                  ((mp4_double)handle->moov->trakAudio->mdia->mdhd->duration /
  6633 		                  (mp4_double)handle->moov->trakAudio->mdia->mdhd->timeScale));
  6634 		}  	
  6635 
  6636   	return 0;
  6637 	}
  6638 
  6639 
  6640 /*
  6641  * Function:
  6642  *
  6643  *   mp4_i32 determineStreamSize(MP4HandleImp handle,
  6644  *                              mp4_u32 *streamsize)
  6645  *
  6646  * Description:
  6647  *
  6648  *   This function determines the size of media data in MP4 file/stream.
  6649  *
  6650  * Parameters:
  6651  *
  6652  *   handle      MP4 library handle
  6653  *   streamsize  Size of data
  6654  *
  6655  * Return value:
  6656  *
  6657  *   0           Success
  6658  *   Negative    Error
  6659  *
  6660  */
  6661 mp4_i32 determineStreamSize(MP4HandleImp handle, mp4_u32 *streamsize)
  6662 {
  6663   *streamsize = 0;
  6664 
  6665   if (!handle->moov)
  6666     return -1;
  6667 
  6668   if ((!handle->moov->trakAudio) && (!handle->moov->trakVideo))
  6669     return -1;
  6670 
  6671   if (handle->moov->trakAudio)
  6672   {
  6673     if (!handle->moov->trakAudio->mdia)
  6674       return -1;
  6675 
  6676     if (!handle->moov->trakAudio->mdia->minf)
  6677       return -1;
  6678 
  6679     if (!handle->moov->trakAudio->mdia->minf->stbl)
  6680       return -1;
  6681 
  6682     if (!handle->moov->trakAudio->mdia->minf->stbl->stsz)
  6683       return -1;
  6684 
  6685     if (handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleSize != 0)
  6686       *streamsize += handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleCount *
  6687                      handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleSize;
  6688     else
  6689     {
  6690       mp4_u32 i;
  6691 
  6692       for (i = 0; i < handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleCount; i++)
  6693         *streamsize += handle->moov->trakAudio->mdia->minf->stbl->stsz->entrySize[i];
  6694     }
  6695   }
  6696 
  6697   if (handle->moov->trakVideo)
  6698   {
  6699     if (!handle->moov->trakVideo->mdia)
  6700       return -1;
  6701 
  6702     if (!handle->moov->trakVideo->mdia->minf)
  6703       return -1;
  6704 
  6705     if (!handle->moov->trakVideo->mdia->minf->stbl)
  6706       return -1;
  6707 
  6708     if (!handle->moov->trakVideo->mdia->minf->stbl->stsz)
  6709       return -1;
  6710 
  6711     if (handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleSize != 0)
  6712       *streamsize += handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount *
  6713                      handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleSize;
  6714     else
  6715     {
  6716       mp4_u32 i;
  6717 
  6718       for (i = 0; i < handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount; i++)
  6719         *streamsize += handle->moov->trakVideo->mdia->minf->stbl->stsz->entrySize[i];
  6720     }
  6721   }
  6722 
  6723   return 0;
  6724 }
  6725 
  6726 
  6727 /*
  6728  * Function:
  6729  *
  6730  *   mp4_i32 determineStreamAverageBitRate(MP4HandleImp handle,
  6731  *                                         mp4_u32 *streamaveragebitrate,
  6732  *                                         mp4_u32 streamsize)
  6733  *
  6734  * Description:
  6735  *
  6736  *   This function determines the average bitrate of the stream in bits per
  6737  *   second.
  6738  *
  6739  *   The average is calculated so that the media data length is divided by
  6740  *   the length of the presentation.
  6741  *
  6742  * Parameters:
  6743  *
  6744  *   handle                MP4 library handle
  6745  *   streamaveragebitrate  Result is returned here
  6746  *   streamsize            Size of media data in bytes
  6747  *
  6748  * Return value:
  6749  *
  6750  *   0           Success
  6751  *   Negative    Error
  6752  *
  6753  */
  6754 mp4_i32 determineStreamAverageBitRate(MP4HandleImp handle, mp4_u32 *streamaveragebitrate, mp4_u32 streamsize)
  6755 {
  6756   if (!handle->moov)
  6757     return -1;
  6758 
  6759   if (!handle->moov->mvhd)
  6760     return -1;
  6761 
  6762   if (!handle->moov->mvhd->timeScale)
  6763     return -1;
  6764 
  6765   if (handle->moov->mvhd->atomhdr->version == 1) /* 64 bit */
  6766       {
  6767       if (!handle->moov->mvhd->duration64)
  6768         return -1;
  6769      
  6770       *streamaveragebitrate = (mp4_u32)((mp4_double)8 * (mp4_double)streamsize /
  6771                                         ((mp4_double)handle->moov->mvhd->duration64 / handle->moov->mvhd->timeScale));      
  6772       }
  6773   else /* 32 bit */
  6774       {
  6775       if (!handle->moov->mvhd->duration)
  6776         return -1;
  6777 
  6778       *streamaveragebitrate = (mp4_u32)((mp4_double)8 * (mp4_double)streamsize /
  6779                                         ((mp4_double)handle->moov->mvhd->duration / handle->moov->mvhd->timeScale));      
  6780       }
  6781 
  6782   return 0;
  6783 }
  6784 
  6785 
  6786 /*
  6787  * Function:
  6788  *
  6789  *   mp4_i32 advanceVideoFrame(MP4HandleImp handle,
  6790  *                             trackAtom *trak)
  6791  *
  6792  * Description:
  6793  *
  6794  *   This function Advances one video frame and finds the frame offset
  6795  *   and size.
  6796  *
  6797  * Parameters:
  6798  *
  6799  *   handle    MP4 library handle
  6800  *   trak      TRAK atom pointer
  6801  *
  6802  * Return value:
  6803  *
  6804  *   0         Success
  6805  *   Negative  Error
  6806  *
  6807  */
  6808 mp4_i32 advanceVideoFrame(MP4HandleImp handle, trackAtom *trak)
  6809 {
  6810   if (!trak->mdia)
  6811     return -1;
  6812   if (!trak->mdia->minf)
  6813     return -1;
  6814   if (!trak->mdia->minf->stbl)
  6815     return -1;
  6816   if (!trak->mdia->minf->stbl->stsz)
  6817     return -1;
  6818 
  6819   /* Are there frames (samples) left? */
  6820 
  6821   if (trak->mdia->minf->stbl->stsz->sampleCount > handle->videoSampleNum)
  6822     handle->videoSampleNum++;
  6823   else
  6824     return -2;
  6825 
  6826   /* Find the size of the frame (sample) */
  6827 
  6828   if (resolveVideoSampleSize(handle, trak->mdia->minf->stbl->stsz) < 0)
  6829     return -1;
  6830 
  6831   /* Find the offset of the frame (sample) */
  6832 
  6833   if (resolveVideoSampleOffset(handle, trak->mdia->minf->stbl) < 0)
  6834     return -1;
  6835 
  6836 
  6837   return 0;
  6838 }
  6839 
  6840 
  6841 /*
  6842  * Function:
  6843  *
  6844  *   mp4_i32 resolveVideoSampleOffset(MP4HandleImp handle,
  6845  *                                    sampleTableAtom *stbl)
  6846  *
  6847  * Description:
  6848  *
  6849  *   This function finds the offset of the current video sample.
  6850  *   The result is stored in handle->videoFrameOffset.
  6851  *
  6852  * Parameters:
  6853  *
  6854  *   handle    MP4 library handle
  6855  *   stbl      STBL atom pointer
  6856  *
  6857  * Return value:
  6858  *
  6859  *   0         Success
  6860  *   Negative  Error
  6861  *
  6862  */
  6863 mp4_i32 resolveVideoSampleOffset(MP4HandleImp handle, sampleTableAtom *stbl)
  6864 	{
  6865 	mp4_u32  chunk;            /* Current chunk number */
  6866 	mp4_u32  sample;           /* Number of samples before this run of chunks */
  6867 	mp4_u32  entry;            /* Current entry in sample to chunk */
  6868 	mp4_u32  chunksInThisRun;  /* Number of chunks in this run */
  6869 	mp4_u32  sampleNrInChunk = 0;	/* Sample number in the chunk */
  6870 
  6871 	if (!stbl->stsc || stbl->stsc->entryCount == 0)
  6872 		{
  6873 		return -1;
  6874 		}
  6875 	
  6876 	if (!stbl->stco || stbl->stco->entryCount == 0)
  6877 		{
  6878 		return -1;
  6879 		}
  6880 
  6881 	chunk = 0;
  6882 	sample = 0;
  6883 	entry = 0;
  6884 
  6885   for (;;)
  6886 		{
  6887 		/* Find how many chunks there are in this run */
  6888 		
  6889 		if (stbl->stsc->entryCount > entry + 1) /* Not last chunk run */
  6890 			{
  6891 			chunksInThisRun = stbl->stsc->firstChunk[entry + 1] - stbl->stsc->firstChunk[entry];
  6892 			}
  6893 		else
  6894 			{
  6895 			chunksInThisRun = stbl->stco->entryCount - chunk + 1;
  6896 			}
  6897 
  6898 		if (handle->videoSampleNum <= chunksInThisRun * stbl->stsc->samplesPerChunk[entry] + sample)
  6899 			{
  6900 			chunk += (handle->videoSampleNum - sample + stbl->stsc->samplesPerChunk[entry] - 1) / stbl->stsc->samplesPerChunk[entry];
  6901 			sampleNrInChunk = (handle->videoSampleNum - sample + stbl->stsc->samplesPerChunk[entry] - 1) % stbl->stsc->samplesPerChunk[entry];
  6902 	  
  6903 			/* The following functions are needed for multiple sample entry support */
  6904 			handle->videoSampleEntryIndex = stbl->stsc->sampleDescriptionIndex[entry];
  6905 
  6906 			break; /* We know the chunk number and sample number in chunk AND the sample entry index of the current sample*/
  6907 			}
  6908 		else
  6909 			{
  6910 			chunk += chunksInThisRun;
  6911 			sample += chunksInThisRun * stbl->stsc->samplesPerChunk[entry];
  6912 			}
  6913 
  6914 	    entry++;
  6915 		}
  6916 
  6917 	if (chunk > stbl->stco->entryCount)
  6918 		{
  6919 		return -1;
  6920 		}
  6921 
  6922 	handle->videoFrameOffset = getChunkOffset(stbl, chunk - 1);
  6923 
  6924 	if (sampleNrInChunk)
  6925 		{
  6926 		if (stbl->stsz->sampleSize)
  6927 			{
  6928 			handle->videoFrameOffset += stbl->stsz->sampleSize * sampleNrInChunk;
  6929 			}
  6930 		else
  6931 			{
  6932 			if (stbl->stsz->sampleCount == 0)
  6933 				{
  6934 				return -1;
  6935 				}
  6936 			while (sampleNrInChunk)
  6937 				{
  6938 				handle->videoFrameOffset += stbl->stsz->entrySize[handle->videoSampleNum - sampleNrInChunk - 1];
  6939 				sampleNrInChunk--;
  6940 				}
  6941 			}
  6942 		}
  6943 		
  6944 		
  6945 	//PRINT((_L("videoFrameOffset %Lu"), handle->videoFrameOffset));
  6946 	return 0;
  6947 	}
  6948 
  6949 
  6950 /*
  6951  * Function:
  6952  *
  6953  *   mp4_i32 resolveVideoSampleSize(MP4HandleImp handle,
  6954  *                                  sampleSizeAtom *stsz)
  6955  *
  6956  * Description:
  6957  *
  6958  *   This function finds the size of the current video sample.
  6959  *   The result is stored in handle->videoFrameSize.
  6960  *
  6961  * Parameters:
  6962  *
  6963  *   handle    MP4 library handle
  6964  *   stsz      STSZ atom pointer
  6965  *
  6966  * Return value:
  6967  *
  6968  *   0         Success
  6969  *   Negative  Error
  6970  *
  6971  */
  6972 mp4_i32 resolveVideoSampleSize(MP4HandleImp handle, sampleSizeAtom *stsz)
  6973 	{
  6974 	if (stsz->sampleSize)
  6975 		{
  6976 		handle->videoFrameSize = stsz->sampleSize;
  6977 		return 0;
  6978 		}
  6979 
  6980 	if (stsz->sampleCount == 0)
  6981 		{
  6982 		return -1;
  6983 		}
  6984 	handle->videoFrameSize = stsz->entrySize[handle->videoSampleNum - 1];
  6985 
  6986 	return 0;
  6987 	}
  6988 
  6989 
  6990 /*
  6991  * Function:
  6992  *
  6993  *   mp4_i32 fetchVideoFrame(MP4HandleImp handle,
  6994  *                           trackAtom *trak,
  6995  *                           mp4_u8 *buffer,
  6996  *                           mp4_u32 buffersize,
  6997  *                           mp4_u32 *framesize,
  6998  *                           mp4_u32 *timestamp,
  6999  *                           mp4_bool *keyframe,
  7000  *                           mp4_u32 *timestamp2)
  7001  *
  7002  * Description:
  7003  *
  7004  *   This function fetches one video frame from a file.
  7005  *
  7006  * Parameters:
  7007  *
  7008  *   handle       MP4 library handle
  7009  *   trak         TRAK atom pointer
  7010  *   buffer       Video frame is retuned here
  7011  *   buffersize   Size of buffer
  7012  *   framesize    Size of returned frame in bytes
  7013  *   timestamp    Frame time in milliseconds (from the beginning of the
  7014  *                presentation)
  7015  *   keyframe     True if intra frame, false otherwise
  7016  *   timestamp2   Frame time in timescale (from the beginning of the
  7017  *                presentation)
  7018  *
  7019  * Return value:
  7020  *
  7021  *   0            Success
  7022  *   Negative     Error
  7023  *
  7024  */
  7025 mp4_i32 fetchVideoFrame(MP4HandleImp handle,
  7026                         trackAtom *trak,
  7027                         mp4_u8 *buffer,
  7028                         mp4_u32 buffersize,
  7029                         mp4_u32 *framesize,
  7030                         mp4_u32 *timestamp,
  7031                         mp4_bool *keyframe,
  7032                         mp4_u32 *timestamp2)
  7033 {
  7034   mp4_i32 bytesread;
  7035 
  7036 
  7037   if (!trak->mdia)
  7038     return -1;
  7039 
  7040   if (handle->file) /* Input is in a file */
  7041   {
  7042     if (seekFileAbs(handle, handle->videoFrameOffset) != 0)
  7043       return -4;
  7044   }
  7045   else /* Input is a stream */
  7046   {
  7047       if (handle->videoFrameOffset + handle->videoFrameSize <= getCumulativeBufferedBytes(handle))
  7048       {
  7049           handle->absPosition = handle->videoFrameOffset;
  7050       }
  7051       else
  7052         return -3;
  7053   }
  7054 
  7055   if (handle->videoFrameSize > buffersize)
  7056   {
  7057     *framesize = handle->videoFrameSize;
  7058     return -2;
  7059   }
  7060 
  7061   bytesread = readData(handle, buffer, handle->videoFrameSize);
  7062   switch (bytesread)
  7063   {
  7064     case -1:
  7065       return -1;
  7066     case -2:
  7067       return -4;
  7068     case -10:
  7069       return -3;
  7070     default:
  7071       break;
  7072   }
  7073 
  7074   if (handle->file)
  7075     if (handle->videoFrameOffset + handle->videoFrameSize - 1 > handle->lastAccessedPosInFile)
  7076       handle->lastAccessedPosInFile = handle->videoFrameOffset + handle->videoFrameSize - 1;
  7077 
  7078   *framesize = handle->videoFrameSize;
  7079 
  7080   if (convertVideoSampleToTime(handle, trak->mdia, timestamp, timestamp2) < 0)
  7081     return -1;
  7082 
  7083   if (isVideoFrameKeyFrame(handle, trak, keyframe) < 0)
  7084     return -1;
  7085 
  7086   return 0;
  7087 }
  7088 
  7089 /*
  7090  * Function:
  7091  *
  7092  *   mp4_i32 fetchVideoFrameAsync(MP4HandleImp handle,
  7093  *                           	  trackAtom *trak,
  7094  *                           	  mp4_u8 *buffer,
  7095  *                           	  mp4_u32 buffersize,
  7096  *
  7097  * Description:
  7098  *
  7099  *   This function fetches one video frame from a file asyncronously.
  7100  *
  7101  * Parameters:
  7102  *
  7103  *   handle       MP4 library handle
  7104  *   trak         TRAK atom pointer
  7105  *   buffer       Video frame is retuned here
  7106  *   buffersize   Size of buffer
  7107  *
  7108  * Return value:
  7109  *
  7110  *   0            Success
  7111  *   Negative     Error
  7112  *
  7113  */
  7114 mp4_i32 fetchVideoFrameAsync(MP4HandleImp handle,
  7115                         trackAtom *trak,
  7116                         mp4_u8 *buffer,
  7117                         mp4_u32 *buffersize)
  7118 {
  7119   if (trak)
  7120 	{
  7121 	if (!trak->mdia)
  7122 		return -1;
  7123 	}
  7124   else
  7125     {
  7126 	return -1;
  7127     }
  7128   
  7129   if (handle->videoFrameSize > *buffersize)
  7130   {
  7131     *buffersize = handle->videoFrameSize;
  7132     return -2;
  7133   }
  7134   
  7135   if ( handle->asyncReader == NULL )
  7136   	{
  7137 	TRAPD(error, handle->asyncReader = CFileAsyncParser::NewL( handle, (RFile64&)handle->rfile ));
  7138 	if ( error != KErrNone )
  7139 		{
  7140 		if (error == KErrNoMemory )
  7141 			{
  7142 			return MP4_OUT_OF_MEMORY;    		
  7143 			}
  7144 		else
  7145 			{
  7146 			return -1;
  7147 			}
  7148 		}  	
  7149   	}
  7150   
  7151   return handle->asyncReader->ReadVideoFrame( buffer, handle->videoFrameOffset, handle->videoFrameSize);
  7152 }
  7153 
  7154 /*
  7155  * Function:
  7156  *
  7157  *   mp4_i32 isVideoFrameKeyFrame(MP4HandleImp handle,
  7158  *                                trackAtom *trak,
  7159  *                                mp4_bool *keyframe)
  7160  *
  7161  * Description:
  7162  *
  7163  *   This function determines if the current frame is a keyframe (intra)
  7164  *   or not.
  7165  *
  7166  * Parameters:
  7167  *
  7168  *   handle       MP4 library handle
  7169  *   trak         TRAK atom pointer
  7170  *   keyframe     Has a value of MP4TRUE if current frame is a keyframe
  7171  *                (intra) or MP4FALSE otherwise
  7172  *
  7173  * Return value:
  7174  *
  7175  *   0            Success
  7176  *   Negative     Error
  7177  *
  7178  */
  7179 mp4_i32 isVideoFrameKeyFrame(MP4HandleImp handle, trackAtom *trak, mp4_bool *keyframe)
  7180 {
  7181   mp4_u32  i;
  7182 
  7183 
  7184   *keyframe = MP4FALSE;
  7185 
  7186   if (!trak->mdia)
  7187     return -1;
  7188 
  7189   if (!trak->mdia->minf)
  7190     return -1;
  7191 
  7192   if (!trak->mdia->minf->stbl)
  7193     return -1;
  7194 
  7195   if (!trak->mdia->minf->stbl->stss)
  7196   {
  7197     *keyframe = MP4TRUE;
  7198 
  7199     return 0;
  7200   }
  7201 
  7202   for (i = 0; i < trak->mdia->minf->stbl->stss->entryCount; i++)
  7203   {
  7204     if (trak->mdia->minf->stbl->stss->sampleNumber[i] == handle->videoSampleNum)
  7205     {
  7206       *keyframe = MP4TRUE;
  7207       break;
  7208     }
  7209   }
  7210 
  7211   return 0;
  7212 }
  7213 
  7214 
  7215 /*
  7216  * Function:
  7217  *
  7218  *   mp4_i32 convertVideoSampleToTime(MP4HandleImp handle,
  7219  *                                    mediaAtom *mdia,
  7220  *                                    mp4_u32 *timestamp,
  7221  *                                    mp4_u32 *timestamp2)
  7222  *
  7223  * Description:
  7224  *
  7225  *   This function converts a video sample to corresponding time.
  7226  *
  7227  * Parameters:
  7228  *
  7229  *   handle       MP4 library handle
  7230  *   mdia         MDIA atom pointer
  7231  *   timestamp    Time in milliseconds is returned here
  7232  *   timestamp2   Time in timescale is returned here
  7233  *
  7234  * Return value:
  7235  *
  7236  *   0            Success
  7237  *   Negative     Error
  7238  *
  7239  */
  7240 mp4_i32 convertVideoSampleToTime(MP4HandleImp handle,
  7241                                  mediaAtom *mdia,
  7242                                  mp4_u32 *timestamp,
  7243                                  mp4_u32 *timestamp2)
  7244 	{
  7245 	mp4_u32      tmptime;
  7246 	mp4_double   tmptime2;
  7247 	mp4_u32      sample;
  7248 	mp4_u32      entry;
  7249 
  7250 	if (!mdia->mdhd)
  7251 		{
  7252 		return -1;
  7253 		}
  7254 	if (!mdia->minf)
  7255 		{
  7256 		return -1;
  7257 		}
  7258 	if (!mdia->minf->stbl)
  7259 		{
  7260 		return -1;
  7261 		}
  7262 	if (!mdia->minf->stbl->stts)
  7263 		{
  7264 		return -1;
  7265 		}
  7266 	if (mdia->minf->stbl->stts->entryCount == 0)
  7267 		{
  7268 		return -1;
  7269 		}
  7270 
  7271 	tmptime = 0;
  7272 	sample = 0;
  7273 	entry = 0;
  7274 
  7275 	for (;;)
  7276 		{
  7277 		if (sample + mdia->minf->stbl->stts->sampleCount[entry] < handle->videoSampleNum)
  7278 			{
  7279 			sample += mdia->minf->stbl->stts->sampleCount[entry];
  7280 			tmptime += (mdia->minf->stbl->stts->sampleCount[entry] * mdia->minf->stbl->stts->sampleDelta[entry]);
  7281 			entry++;
  7282 			if (entry == mdia->minf->stbl->stts->entryCount)
  7283 				{
  7284 				return -1;
  7285 				}
  7286 			}
  7287 		else
  7288 			{
  7289 			tmptime += ((handle->videoSampleNum - sample - 1) * mdia->minf->stbl->stts->sampleDelta[entry]);
  7290 			break;
  7291 			}
  7292 		}
  7293 	
  7294   	if (mdia->mdhd->timeScale == 0)
  7295   		{
  7296   		return -1;
  7297   		}
  7298 
  7299   	if (timestamp2)
  7300   		{
  7301   		*timestamp2 = tmptime;
  7302   		}
  7303 
  7304   	tmptime2 = (mp4_double)tmptime * (mp4_double)1000 / (mp4_double)mdia->mdhd->timeScale + (mp4_double)0.5;
  7305 
  7306   	*timestamp = (mp4_u32)tmptime2;
  7307 
  7308   	return 0;
  7309 	}
  7310 
  7311 
  7312 /*
  7313  * Function:
  7314  *
  7315  *   mp4_i32 advanceAudioSample(MP4HandleImp handle,
  7316  *                              trackAtom *trak)
  7317  *
  7318  * Description:
  7319  *
  7320  *   This function advances one audio sample and finds the sample
  7321  *   offset and sample size.
  7322  *
  7323  * Parameters:
  7324  *
  7325  *   handle    MP4 library handle
  7326  *   trak      TRAK atom pointer
  7327  *
  7328  * Return value:
  7329  *
  7330  *   0         Success
  7331  *   Negative  Error
  7332  *
  7333  */
  7334 mp4_i32 advanceAudioSample(MP4HandleImp handle,
  7335                            trackAtom *trak)
  7336 {
  7337   if (!trak->mdia)
  7338     return -1;
  7339   if (!trak->mdia->minf)
  7340     return -1;
  7341   if (!trak->mdia->minf->stbl)
  7342     return -1;
  7343   if (!trak->mdia->minf->stbl->stsz)
  7344     return -1;
  7345 
  7346 
  7347   /* Are there samples left? */
  7348 
  7349   if (trak->mdia->minf->stbl->stsz->sampleCount > handle->audioSampleNum)
  7350     handle->audioSampleNum++;
  7351   else
  7352     return -2;
  7353 
  7354   /* Find the size of the sample */
  7355 
  7356   if (resolveAudioSampleSize(handle, trak->mdia->minf->stbl->stsz) < 0)
  7357     return -1;
  7358 
  7359   /* Find the offset of the sample */
  7360 
  7361   if (resolveAudioSampleOffset(handle, trak->mdia->minf->stbl) < 0)
  7362     return -1;
  7363 
  7364 
  7365   return 0;
  7366 }
  7367 
  7368 
  7369 /*
  7370  * Function:
  7371  *
  7372  *   mp4_i32 resolveAudioSampleOffset(MP4HandleImp handle,
  7373  *                                    sampleTableAtom *stbl)
  7374  *
  7375  * Description:
  7376  *
  7377  *   This function finds the offset of the current audio sample.
  7378  *   The result is stored in handle->audioSampleOffset.
  7379  *
  7380  * Parameters:
  7381  *
  7382  *   handle    MP4 library handle
  7383  *   stbl      STBL atom pointer
  7384  *
  7385  * Return value:
  7386  *
  7387  *   0         Success
  7388  *   Negative  Error
  7389  *
  7390  */
  7391 mp4_i32 resolveAudioSampleOffset(MP4HandleImp handle, sampleTableAtom *stbl)
  7392 {
  7393   mp4_u32  chunk;            /* Current chunk number */
  7394   mp4_u32  sample;            /* Number of samples before this run of chunks */
  7395   mp4_u32  entry;            /* Current entry in sample to chunk */
  7396   mp4_u32 chunksInThisRun;  /* Number of chunks in this run */
  7397   mp4_u32  sampleNrInChunk;  /* Sample number in the chunk */
  7398 
  7399 
  7400   if (!stbl->stsc || stbl->stsc->entryCount == 0)
  7401     return -1;
  7402   if (!stbl->stco || stbl->stco->entryCount == 0)
  7403     return -1;
  7404 
  7405   chunk = 0;
  7406   sample = 0;
  7407   entry = 0;
  7408 
  7409   for (;;)
  7410   {
  7411     /* Find how many chunks there are in this run */
  7412 
  7413     if (stbl->stsc->entryCount > entry + 1) /* Not last chunk run */
  7414     {
  7415       chunksInThisRun = stbl->stsc->firstChunk[entry + 1] -
  7416                         stbl->stsc->firstChunk[entry];
  7417     }
  7418     else
  7419       chunksInThisRun = stbl->stco->entryCount - chunk + 1;
  7420 
  7421 
  7422     if (handle->audioSampleNum <= chunksInThisRun * stbl->stsc->samplesPerChunk[entry] + sample)
  7423     {
  7424       chunk += (handle->audioSampleNum - sample + stbl->stsc->samplesPerChunk[entry] - 1) / stbl->stsc->samplesPerChunk[entry];
  7425       sampleNrInChunk = (handle->audioSampleNum - sample + stbl->stsc->samplesPerChunk[entry] - 1) % stbl->stsc->samplesPerChunk[entry];
  7426 
  7427 	  /* The following functions are needed for multiple sample entry support */
  7428 	  handle->audioSampleEntryIndex = stbl->stsc->sampleDescriptionIndex[entry];
  7429 
  7430       break; /* We know the chunk number and sample number in chunk AND the sample entry index of the current sample*/
  7431     }
  7432     else
  7433     {
  7434       chunk += chunksInThisRun;
  7435       sample += chunksInThisRun * stbl->stsc->samplesPerChunk[entry];
  7436     }
  7437 
  7438     entry++;
  7439   }
  7440 
  7441   if (chunk > stbl->stco->entryCount)
  7442     return -1;
  7443 
  7444   handle->audioSampleOffset = getChunkOffset(stbl, chunk - 1);
  7445 
  7446   	if (sampleNrInChunk)
  7447   		{
  7448   		if (stbl->stsz->sampleSize)
  7449   			{
  7450   			handle->audioSampleOffset += stbl->stsz->sampleSize * sampleNrInChunk;
  7451   			}
  7452   		else
  7453   			{
  7454   			if (stbl->stsz->sampleCount == 0)
  7455   				{
  7456   				// ensure there are entries in the entrySize array
  7457   				return -1;
  7458   				}
  7459     
  7460   			while (sampleNrInChunk)
  7461   				{
  7462   				handle->audioSampleOffset += stbl->stsz->entrySize[handle->audioSampleNum - sampleNrInChunk - 1];
  7463   				sampleNrInChunk--;
  7464   				}
  7465   			}
  7466   		}
  7467   		
  7468   //PRINT((_L("audioSampleOffset %Lu"), handle->audioSampleOffset));
  7469   return 0;
  7470 }
  7471 
  7472 
  7473 /*
  7474  * Function:
  7475  *
  7476  *   mp4_i32 resolveAudioSampleSize(MP4HandleImp handle,
  7477  *                                  sampleSizeAtom *stsz)
  7478  *
  7479  * Description:
  7480  *
  7481  *   This function finds the size of the current audio sample.
  7482  *   The result is stored in handle->audioSampleSize.
  7483  *
  7484  * Parameters:
  7485  *
  7486  *   handle    MP4 library handle
  7487  *   stsz      STSZ atom pointer
  7488  *
  7489  * Return value:
  7490  *
  7491  *   0         Success
  7492  *   Negative  Error
  7493  *
  7494  */
  7495 mp4_i32 resolveAudioSampleSize(MP4HandleImp handle, sampleSizeAtom *stsz)
  7496 	{
  7497 	if (stsz->sampleSize)
  7498 		{
  7499 		handle->audioSampleSize = stsz->sampleSize;
  7500 		return 0;
  7501 		}
  7502 
  7503 	if (stsz->sampleCount == 0)
  7504 		{
  7505 		return -1;
  7506 		}
  7507 	handle->audioSampleSize = stsz->entrySize[handle->audioSampleNum - 1];
  7508 
  7509 	return 0;
  7510 	}
  7511 
  7512 
  7513 /*
  7514  * Function:
  7515  *
  7516  *   mp4_i32 fetchAudioSample(MP4HandleImp handle,
  7517  *                            trackAtom *trak,
  7518  *                            mp4_u8 *buffer,
  7519  *                            mp4_u32 buffersize,
  7520  *                            mp4_u32 *framesize,
  7521  *                            mp4_u32 *timestamp,
  7522  *                            mp4_u32 *returnedframes,
  7523  *                            mp4_u32 *timestamp2)
  7524  *
  7525  * Description:
  7526  *
  7527  *   This function fetches one audio sample from a file.
  7528  *
  7529  *   Note: returnedframes may differ from the correct value when accessing
  7530  *         the last audio sample.
  7531  *
  7532  * Parameters:
  7533  *
  7534  *   handle           MP4 library handle
  7535  *   trak             TRAK atom pointer
  7536  *   buffer           Audio frame is retuned here
  7537  *   buffersize       Size of buffer
  7538  *   framesize        Size of returned frame in bytes
  7539  *   timestamp        Frame time in milliseconds (from the beginning of the
  7540  *                    presentation)
  7541  *   returnedframes   Number of frames returned, of 0 if not known
  7542  *   timestamp2       Frame time in timescale (from the beginning of the
  7543  *                    presentation)
  7544  *
  7545  * Return value:
  7546  *
  7547  *   0                Success
  7548  *   Negative         Error
  7549  *
  7550  */
  7551 mp4_i32 fetchAudioSample(MP4HandleImp handle,
  7552                          trackAtom *trak,
  7553                          mp4_u8 *buffer,
  7554                          mp4_u32 buffersize,
  7555                          mp4_u32 *framesize,
  7556                          mp4_u32 *timestamp,
  7557                          mp4_u32 *returnedframes,
  7558                          mp4_u32 *timestamp2)
  7559 {
  7560   mp4_i32 bytesread;
  7561   mp4_i32 frameLength;
  7562   mp4_u32 numOfFrames;
  7563   mp4_u8 *framepointer;
  7564   mp4_u32 rawAmrFrameLength[16] = {13,14,16,18,20,21,27,32,6,0,0,0,0,0,0,1};
  7565 
  7566   if (!trak->mdia)
  7567     return -1;
  7568 
  7569   if (handle->file) /* Input is in a file */
  7570   {
  7571     if (seekFileAbs(handle, handle->audioSampleOffset) != 0)
  7572       return -4;
  7573   }
  7574   else /* Input is a stream */
  7575   {
  7576       if (handle->audioSampleOffset + handle->audioSampleSize <= getCumulativeBufferedBytes(handle))
  7577       {
  7578           handle->absPosition = handle->audioSampleOffset;
  7579       }
  7580       else
  7581         return -3;
  7582   }
  7583 
  7584   if (handle->audioSampleSize > buffersize)
  7585   {
  7586     *framesize = handle->audioSampleSize;
  7587     return -2;
  7588   }
  7589 
  7590   bytesread = readData(handle, buffer, handle->audioSampleSize);
  7591   switch (bytesread)
  7592   {
  7593     case -1:
  7594       return -1;
  7595     case -2:
  7596       return -4;
  7597     case -10:
  7598       return -3;
  7599     default:
  7600       break;
  7601   }
  7602 
  7603   if (handle->file)
  7604     if (handle->audioSampleOffset + handle->audioSampleSize - 1 > handle->lastAccessedPosInFile)
  7605       handle->lastAccessedPosInFile = handle->audioSampleOffset + handle->audioSampleSize - 1;
  7606 
  7607   *framesize = handle->audioSampleSize;
  7608   if (convertAudioSampleToTime(handle, trak->mdia, timestamp, timestamp2) < 0)
  7609     return -1;
  7610 
  7611   *returnedframes = 0;
  7612 
  7613   /* AMR */
  7614   if (trak->mdia->minf)
  7615     if (trak->mdia->minf->stbl)
  7616       if (trak->mdia->minf->stbl->stsd)
  7617         if (handle->type & MP4_TYPE_AMR_NB)
  7618         {
  7619             framepointer = buffer;
  7620             numOfFrames = 0;
  7621             while ( bytesread > 0 )
  7622             {
  7623                 frameLength = rawAmrFrameLength[(TInt)(((*framepointer) & 0x78) >> 3)];
  7624                 if ( frameLength == 0)
  7625                 {
  7626                     return -4;
  7627                 }
  7628                 bytesread -= frameLength;
  7629                 framepointer += frameLength;
  7630                 numOfFrames++;
  7631             }
  7632             *returnedframes = numOfFrames;
  7633 
  7634 		  /* Return the number of sample entries listed for this particular sample entry index 
  7635           if (trak->mdia->minf->stbl->stsd->samr[handle->audioSampleEntryIndex - 1])
  7636             if (trak->mdia->minf->stbl->stsd->samr[handle->audioSampleEntryIndex - 1]->damr)
  7637               *returnedframes = trak->mdia->minf->stbl->stsd->samr[handle->audioSampleEntryIndex - 1]->damr->framesPerSample;*/
  7638         }
  7639         else if (handle->type & MP4_TYPE_AMR_WB)
  7640         {
  7641 		  /* Return the number of sample entries listed for this particular sample entry index */
  7642           if (trak->mdia->minf->stbl->stsd->sawb[handle->audioSampleEntryIndex - 1])
  7643             if (trak->mdia->minf->stbl->stsd->sawb[handle->audioSampleEntryIndex - 1]->damr)
  7644               *returnedframes = trak->mdia->minf->stbl->stsd->sawb[handle->audioSampleEntryIndex - 1]->damr->framesPerSample;
  7645         }
  7646         else
  7647         {
  7648         }
  7649 
  7650   /* MPEG-4 audio */
  7651   if (trak->mdia->minf)
  7652     if (trak->mdia->minf->stbl)
  7653       if (trak->mdia->minf->stbl->stsd)
  7654         if (trak->mdia->minf->stbl->stsd->mp4a[handle->audioSampleEntryIndex - 1])
  7655           *returnedframes = 1;
  7656 
  7657   /* QCELP 13K as QCELPSampleEntry*/
  7658   if (trak->mdia->minf)
  7659     if (trak->mdia->minf->stbl)
  7660       if (trak->mdia->minf->stbl->stsd)
  7661         if ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio))
  7662         {
  7663 		  /* Return the number of sample entries listed for this particular sample entry index */
  7664           if (trak->mdia->minf->stbl->stsd->sqcp[handle->audioSampleEntryIndex - 1])
  7665             if (trak->mdia->minf->stbl->stsd->sqcp[handle->audioSampleEntryIndex - 1]->dqcp)
  7666               *returnedframes = trak->mdia->minf->stbl->stsd->sqcp[handle->audioSampleEntryIndex - 1]->dqcp->framesPerSample;
  7667         }
  7668 
  7669   /* QCELP 13K as MPEG-4 audio */
  7670   if (trak->mdia->minf)
  7671     if (trak->mdia->minf->stbl)
  7672       if (trak->mdia->minf->stbl->stsd)
  7673         if (trak->mdia->minf->stbl->stsd->mp4a[handle->audioSampleEntryIndex - 1])
  7674           *returnedframes = 1;
  7675 
  7676   return 0;
  7677 }
  7678 
  7679 /*
  7680  * Function:
  7681  *
  7682  *   mp4_i32 fetchAudioSampleAsync(MP4HandleImp handle,
  7683  *                            trackAtom *trak,
  7684  *                            mp4_u8 *buffer,
  7685  *                            mp4_u32 buffersize,
  7686  *
  7687  * Description:
  7688  *
  7689  *   This function fetches one audio sample from a file asyncronously.
  7690  *
  7691  * Parameters:
  7692  *
  7693  *   handle           MP4 library handle
  7694  *   trak             TRAK atom pointer
  7695  *   buffer           Audio frame is retuned here
  7696  *   buffersize       Size of buffer
  7697  *
  7698  * Return value:
  7699  *
  7700  *   0                Success
  7701  *   Negative         Error
  7702  *
  7703  */
  7704 mp4_i32 fetchAudioSampleAsync(MP4HandleImp handle,
  7705                          	  trackAtom *trak,
  7706                          	  mp4_u8 *buffer,
  7707                          	  mp4_u32 *buffersize)
  7708 {
  7709   if (trak)
  7710 	{
  7711 	if (!trak->mdia)
  7712 		return -1;
  7713 	}
  7714   else
  7715     {
  7716 	return -1;
  7717     }
  7718   
  7719   if (handle->audioSampleSize > *buffersize)
  7720 		{
  7721 		*buffersize = handle->audioSampleSize;
  7722 		return -2;
  7723 		}
  7724   
  7725   if (!handle->file) // Other input than file is not supported
  7726 	  {
  7727 	  return -1;
  7728 	  }
  7729   
  7730   if ( handle->asyncReader == NULL )
  7731   	{
  7732 	TRAPD(error, handle->asyncReader = CFileAsyncParser::NewL( handle, (RFile64&)handle->rfile ));
  7733 	if ( error != KErrNone )
  7734 		{
  7735 		if (error == KErrNoMemory )
  7736 			{
  7737 			return MP4_OUT_OF_MEMORY;    		
  7738 			}
  7739 		else
  7740 			{
  7741 			return -1;
  7742 			}
  7743 		}  	
  7744   	}
  7745     
  7746   return handle->asyncReader->ReadAudioFrames( buffer, handle->audioSampleOffset, handle->audioSampleSize);
  7747 }
  7748 
  7749 /*
  7750  * Function:
  7751  *
  7752  *   mp4_i32 convertAudioSampleToTime(MP4HandleImp handle,
  7753  *                                    mediaAtom *mdia,
  7754  *                                    mp4_u32 *timestamp,
  7755  *                                    mp4_u32 *timestamp2)
  7756  *
  7757  * Description:
  7758  *
  7759  *   This function converts an audio sample to corresponding time.
  7760  *
  7761  * Parameters:
  7762  *
  7763  *   handle       MP4 library handle
  7764  *   mdia         MDIA atom pointer
  7765  *   timestamp    Time in milliseconds is returned here
  7766  *   timestamp2   Time in timescale is returned here
  7767  *
  7768  * Return value:
  7769  *
  7770  *   0            Success
  7771  *   Negative     Error
  7772  *
  7773  */
  7774 mp4_i32 convertAudioSampleToTime(MP4HandleImp handle,
  7775                                  mediaAtom *mdia,
  7776                                  mp4_u32 *timestamp,
  7777                                  mp4_u32 *timestamp2)
  7778 	{
  7779 	mp4_u32      tmptime;
  7780 	mp4_double  tmptime2;
  7781 	mp4_u32      sample;
  7782 	mp4_u32      entry;
  7783 
  7784   	if (!mdia->mdhd)
  7785   		{
  7786   		return -1;
  7787   		}
  7788   	if (!mdia->minf)
  7789   		{
  7790   		return -1;
  7791   		}
  7792   	if (!mdia->minf->stbl)
  7793   		{
  7794   		return -1;
  7795   		}
  7796   	if (!mdia->minf->stbl->stts)
  7797   		{
  7798   		return -1;
  7799   		}
  7800   	if (mdia->minf->stbl->stts->entryCount == 0)
  7801   		{
  7802   		return -1;
  7803   		}
  7804 
  7805   	tmptime = 0;
  7806   	sample = 0;
  7807   	entry = 0;
  7808 
  7809   	for (;;)
  7810   		{
  7811   		if (sample + mdia->minf->stbl->stts->sampleCount[entry] < handle->audioSampleNum)
  7812   			{
  7813   			sample += mdia->minf->stbl->stts->sampleCount[entry];
  7814   			tmptime += mdia->minf->stbl->stts->sampleCount[entry] *
  7815                  	mdia->minf->stbl->stts->sampleDelta[entry];
  7816   			entry++;
  7817   			
  7818   			if (entry == mdia->minf->stbl->stts->entryCount)
  7819   				return -1;
  7820   			}
  7821   		else
  7822   			{
  7823   			tmptime += (handle->audioSampleNum - sample - 1) * mdia->minf->stbl->stts->sampleDelta[entry];
  7824   			break;
  7825   			}
  7826   		}
  7827 
  7828   	if (mdia->mdhd->timeScale == 0)
  7829   		{
  7830   		return -1;
  7831   		}
  7832 
  7833   	if (timestamp2)
  7834   		{
  7835   		*timestamp2 = tmptime;
  7836   		}
  7837 
  7838   	tmptime2 = (mp4_double)tmptime * (mp4_double)1000 / (mp4_double)mdia->mdhd->timeScale + (mp4_double)0.5;
  7839 
  7840   	*timestamp = (mp4_u32)tmptime2;
  7841 
  7842   	return 0;
  7843 	}
  7844 
  7845 
  7846 /*
  7847  * Function:
  7848  *
  7849  *   mp4_i32 convertTimeToSample(MP4HandleImp handle,
  7850  *                               trackAtom *trak,
  7851  *                               mp4_u32 position,
  7852  *                               mp4_u32 *sample)
  7853  *
  7854  * Description:
  7855  *
  7856  *   This function converts time to corresponding sample number.
  7857  *
  7858  * Parameters:
  7859  *
  7860  *   handle       MP4 library handle
  7861  *   trak         trackAtom pointer
  7862  *   position     Time in milliseconds
  7863  *   sample       Sample number is returned here
  7864  *
  7865  * Return value:
  7866  *
  7867  *   0            Success
  7868  *   Negative     Error
  7869  *
  7870  */
  7871 mp4_i32 convertTimeToSample(MP4HandleImp handle,
  7872                             trackAtom *trak,
  7873                             mp4_u32 position,
  7874                             mp4_u32 *sample)
  7875 {
  7876   mp4_u32 pos;      /* Target position in media timescale */
  7877   mp4_u32 tmppos;   /* Temporary position counter */
  7878   mp4_u32 i;
  7879 
  7880 
  7881   if (!handle)
  7882     return -1;
  7883   if (!trak)
  7884     return -1;
  7885   if (!trak->mdia)
  7886     return -1;
  7887   if (!trak->mdia->mdhd)
  7888     return -1;
  7889   if (!trak->mdia->minf)
  7890     return -1;
  7891   if (!trak->mdia->minf->stbl)
  7892     return -1;
  7893   if (!trak->mdia->minf->stbl->stts)
  7894     return -1;
  7895   if (trak->mdia->minf->stbl->stts->entryCount == 0)
  7896     return -1;
  7897 
  7898   *sample = 1;
  7899   tmppos = 0;
  7900 
  7901   pos = (mp4_u32)((mp4_double)position / (mp4_double)1000 * (mp4_double)trak->mdia->mdhd->timeScale + (mp4_double)0.5);
  7902 
  7903   for (i = 0; i < trak->mdia->minf->stbl->stts->entryCount; i++)
  7904   {
  7905     if (pos >= (tmppos + trak->mdia->minf->stbl->stts->sampleCount[i] *
  7906                          trak->mdia->minf->stbl->stts->sampleDelta[i]))
  7907     {
  7908       *sample += trak->mdia->minf->stbl->stts->sampleCount[i];
  7909       tmppos += (trak->mdia->minf->stbl->stts->sampleCount[i] *
  7910                  trak->mdia->minf->stbl->stts->sampleDelta[i]);
  7911 
  7912       if (i == trak->mdia->minf->stbl->stts->entryCount - 1) /* Last entry */
  7913         *sample = *sample - 1;
  7914     }
  7915     else
  7916     {
  7917       if (trak->mdia->minf->stbl->stts->sampleDelta[i] == 0)
  7918         return -1;
  7919 
  7920       *sample += ((pos - tmppos) / trak->mdia->minf->stbl->stts->sampleDelta[i]);
  7921 
  7922       break;
  7923     }
  7924   }
  7925 
  7926   return 0;
  7927 }
  7928 
  7929 
  7930 /*
  7931  * Function:
  7932  *
  7933  *   mp4_i32 goToVideoSample(MP4HandleImp handle,
  7934  *                           trackAtom *trak,
  7935  *                           mp4_u32 sample)
  7936  *
  7937  * Description:
  7938  *
  7939  *   This function moves to video sample indicated by sample and finds the
  7940  *   sample offset and sample size.
  7941  *
  7942  * Parameters:
  7943  *
  7944  *   handle    MP4 library handle
  7945  *   trak      TRAK atom pointer
  7946  *   sample    Sample to go to
  7947  *
  7948  * Return value:
  7949  *
  7950  *   0         Success
  7951  *   Negative  Error
  7952  *
  7953  */
  7954 mp4_i32 goToVideoSample(MP4HandleImp handle,
  7955                         trackAtom *trak,
  7956                         mp4_u32 sample)
  7957 {
  7958   if (!trak->mdia)
  7959     return -1;
  7960   if (!trak->mdia->minf)
  7961     return -1;
  7962   if (!trak->mdia->minf->stbl)
  7963     return -1;
  7964   if (!trak->mdia->minf->stbl->stsz)
  7965     return -1;
  7966 
  7967 
  7968   /* Is the sample valid? */
  7969 
  7970   if (sample <= trak->mdia->minf->stbl->stsz->sampleCount)
  7971     handle->videoSampleNum = sample;
  7972   else
  7973     return -1;
  7974 
  7975   /* Find the size of the sample */
  7976 
  7977   if (resolveVideoSampleSize(handle, trak->mdia->minf->stbl->stsz) < 0)
  7978     return -1;
  7979 
  7980   /* Find the offset of the sample */
  7981 
  7982   if (resolveVideoSampleOffset(handle, trak->mdia->minf->stbl) < 0)
  7983     return -1;
  7984 
  7985 
  7986   return 0;
  7987 }
  7988 
  7989 
  7990 /*
  7991  * Function:
  7992  *
  7993  *   mp4_i32 goToAudioSample(MP4HandleImp handle,
  7994  *                           trackAtom *trak,
  7995  *                           mp4_u32 sample)
  7996  *
  7997  * Description:
  7998  *
  7999  *   This function moves to audio sample indicated by sample and finds the
  8000  *   sample offset and sample size.
  8001  *
  8002  * Parameters:
  8003  *
  8004  *   handle    MP4 library handle
  8005  *   trak      TRAK atom pointer
  8006  *   sample    Sample to go to
  8007  *
  8008  * Return value:
  8009  *
  8010  *   0         Success
  8011  *   Negative  Error
  8012  *
  8013  */
  8014 mp4_i32 goToAudioSample(MP4HandleImp handle,
  8015                         trackAtom *trak,
  8016                         mp4_u32 sample)
  8017 {
  8018   if (!trak->mdia)
  8019     return -1;
  8020   if (!trak->mdia->minf)
  8021     return -1;
  8022   if (!trak->mdia->minf->stbl)
  8023     return -1;
  8024   if (!trak->mdia->minf->stbl->stsz)
  8025     return -1;
  8026 
  8027 
  8028   /* Is the sample valid? */
  8029 
  8030   if (sample <= trak->mdia->minf->stbl->stsz->sampleCount)
  8031     handle->audioSampleNum = sample;
  8032   else
  8033     return -1;
  8034 
  8035   /* Find the size of the sample */
  8036 
  8037   if (resolveAudioSampleSize(handle, trak->mdia->minf->stbl->stsz) < 0)
  8038     return -1;
  8039 
  8040   /* Find the offset of the sample */
  8041 
  8042   if (resolveAudioSampleOffset(handle, trak->mdia->minf->stbl) < 0)
  8043     return -1;
  8044 
  8045 
  8046   return 0;
  8047 }
  8048 
  8049 
  8050 /*
  8051  * Function:
  8052  *
  8053  *   mp4_i32 findVideoKeyFrame(MP4HandleImp handle,
  8054  *                             trackAtom *trak,
  8055  *                             mp4_u32 sample,
  8056  *                             mp4_u32 *newsample)
  8057  *
  8058  * Description:
  8059  *
  8060  *   This function finds the video keyframe that is identical to or precedes
  8061  *   the sample indicated by sample.
  8062  *
  8063  * Parameters:
  8064  *
  8065  *   handle       MP4 library handle
  8066  *   trak         TRAK atom pointer
  8067  *   sample       Sample number
  8068  *   newsample    Sample number of found keyframe
  8069  *
  8070  * Return value:
  8071  *
  8072  *   0            Success
  8073  *   Negative     Error
  8074  *
  8075  */
  8076 mp4_i32 findVideoKeyFrame(MP4HandleImp handle,
  8077                           trackAtom *trak,
  8078                           mp4_u32 sample,
  8079                           mp4_u32 *newsample)
  8080 {
  8081   mp4_i32  i;
  8082 
  8083 
  8084   if (!handle)
  8085     return -1;
  8086   if (!trak->mdia)
  8087     return -1;
  8088   if (!trak->mdia->minf)
  8089     return -1;
  8090   if (!trak->mdia->minf->stbl)
  8091     return -1;
  8092 
  8093   if (!trak->mdia->minf->stbl->stss) /* No sync sample atom => all samples are
  8094                                         random access points */
  8095   {
  8096     *newsample = sample;
  8097 
  8098     return 0;
  8099   }
  8100   *newsample = 0;
  8101 
  8102   for (i = trak->mdia->minf->stbl->stss->entryCount - 1; i >= 0; i--)
  8103   {
  8104     if (sample >= trak->mdia->minf->stbl->stss->sampleNumber[i])
  8105     {
  8106       *newsample = trak->mdia->minf->stbl->stss->sampleNumber[i];
  8107       break;
  8108     }
  8109   }
  8110 
  8111   if (*newsample == 0)
  8112     return -1;
  8113 
  8114   return 0;
  8115 }
  8116 
  8117 
  8118 /*
  8119  * Function:
  8120  *
  8121  *   mp4_i32 readAVCC(MP4HandleImp handle,
  8122  *                    avcConfigurationAtom *avcc)
  8123  *
  8124  * Description:
  8125  *
  8126  *   This function parses one avcc atom.
  8127  *
  8128  * Parameters:
  8129  *
  8130  *   handle             MP4 library handle
  8131  *   avcc               avcC pointer
  8132  *
  8133  * Return value:
  8134  *
  8135  *   Negative integer   Error
  8136  *   >= 0               Success. Value tells how many bytes were read.
  8137  *
  8138  */
  8139 mp4_i32 readAVCC(MP4HandleImp handle, avcConfigurationAtom *avcc)
  8140 {
  8141 	mp4_i32 bytesread;
  8142 	mp4_i32 totalbytesread = 0;
  8143 
  8144 	avcc->avcConfigSize = 0;
  8145 
  8146 	if ((avcc->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  8147 		return -100;
  8148 
  8149 	bytesread = readAtomHeader(handle, avcc->atomhdr);
  8150 	if (bytesread < 0)
  8151 		return -1;
  8152 	totalbytesread +=bytesread;
  8153 
  8154 	if (avcc->atomhdr->type != ATOMTYPE_AVCC)
  8155 		return -1;
  8156 
  8157     /* read the avcDecoderConfigurationRecord */
  8158     if  (avcc->atomhdr->size != 1)
  8159     	avcc->avcConfigSize = avcc->atomhdr->size - 8;
  8160     else
  8161     	avcc->avcConfigSize = (mp4_u32)(I64INT(avcc->atomhdr->largeSize) - 16);
  8162 
  8163    	avcc->avcConfig = (mp4_u8 *)mp4malloc(avcc->avcConfigSize);
  8164 	if (avcc->avcConfig == 0)
  8165 		return -100;
  8166 	
  8167 	bytesread = readData(handle, avcc->avcConfig, avcc->avcConfigSize );
  8168     
  8169 	if (bytesread < 0)
  8170 		return -1;
  8171 	totalbytesread +=bytesread;
  8172 	return totalbytesread;
  8173 }
  8174 
  8175 
  8176 /*
  8177  * Function:
  8178  *
  8179  *   mp4_i32 readBTRT(MP4HandleImp handle,
  8180  *                    mpeg4BitrateAtom *btrt)
  8181  *
  8182  * Description:
  8183  *
  8184  *   This function parses one btrt atom.
  8185  *
  8186  * Parameters:
  8187  *
  8188  *   handle             MP4 library handle
  8189  *   btrt					btrt pointer
  8190  *
  8191  * Return value:
  8192  *
  8193  *   Negative integer   Error
  8194  *   >= 0               Success. Value tells how many bytes were read.
  8195  *
  8196  */
  8197 mp4_i32 readBTRT(MP4HandleImp handle, mpeg4BitrateAtom *btrt)
  8198 {
  8199 	mp4_i32 bytesread;
  8200 	mp4_i32 totalbytesread = 0;
  8201 
  8202 
  8203 	if ((btrt->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  8204 		return -100;
  8205 
  8206 	bytesread = readAtomHeader(handle, btrt->atomhdr);
  8207 	if (bytesread < 0)
  8208 		return -1;
  8209 	totalbytesread +=bytesread;
  8210 
  8211 	if (btrt->atomhdr->type != ATOMTYPE_BTRT)
  8212 		return -1;
  8213 
  8214     /* read the mpeg4BitrateAtom */
  8215    bytesread = readData(handle, handle->buf, 4);
  8216    if (bytesread < 0)
  8217 	   return -1;
  8218    btrt->bufferSizeDB = u32endian(*((mp4_u32 *)handle->buf));
  8219    totalbytesread +=bytesread;
  8220 
  8221    bytesread = readData(handle, handle->buf, 4);
  8222    if (bytesread < 0)
  8223 	   return -1;
  8224    btrt->maxBitRate = u32endian(*((mp4_u32 *)handle->buf));
  8225    totalbytesread +=bytesread;
  8226 
  8227    bytesread = readData(handle, handle->buf, 4);
  8228    if (bytesread < 0)
  8229 	   return -1;
  8230    btrt->avgBitrate = u32endian(*((mp4_u32 *)handle->buf));
  8231    totalbytesread +=bytesread;
  8232 
  8233 	return totalbytesread;
  8234 }
  8235 
  8236 /*
  8237  * Function:
  8238  *
  8239  *   mp4_i32 readM4DS(MP4HandleImp handle,
  8240  *                    mpeg4ExtensionDescriptorsAtom *m4ds)
  8241  *
  8242  * Description:
  8243  *
  8244  *   This function parses one m4ds atom.
  8245  *
  8246  * Parameters:
  8247  *
  8248  *   handle             MP4 library handle
  8249  *   m4ds               m4ds pointer
  8250  *
  8251  * Return value:
  8252  *
  8253  *   Negative integer   Error
  8254  *   >= 0               Success. Value tells how many bytes were read.
  8255  *
  8256  */
  8257 mp4_i32 readM4DS(MP4HandleImp handle, mpeg4ExtensionDescriptorsAtom *m4ds)
  8258 {
  8259 	mp4_i32 bytesread;
  8260 	mp4_i32 totalbytesread = 0;
  8261 	mp4_u32 i;
  8262 
  8263 	m4ds->descrSize = 0;
  8264 
  8265 	if ((m4ds->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  8266 		return -100;
  8267 
  8268 	bytesread = readAtomHeader(handle, m4ds->atomhdr);
  8269 	if (bytesread < 0)
  8270 		return -1;
  8271 	totalbytesread +=bytesread;
  8272 
  8273 	if (m4ds->atomhdr->type != ATOMTYPE_M4DS)
  8274 		return -1;
  8275 
  8276     /* read the avcDecoderConfigurationRecord */
  8277 	if  (m4ds->atomhdr->size != 1)
  8278 		bytesread = readData(handle, handle->buf, m4ds->atomhdr->size - 8);
  8279 	else
  8280         bytesread = readData(handle, handle->buf, (mp4_u32)(I64INT(m4ds->atomhdr->largeSize) - 16) );
  8281 
  8282 	if (bytesread < 0)
  8283 		return -1;
  8284 	m4ds->descrSize = bytesread;
  8285 	m4ds->descr = (mp4_u8 *)mp4malloc(m4ds->descrSize * sizeof(mp4_u8));
  8286 	
  8287 	/* copy the mpeg4ExtensionDescriptors from the temp. buffer */
  8288 	for(i = 0; i <  m4ds->descrSize; i++)
  8289 		m4ds->descr[i] = handle->buf[i];
  8290 	
  8291 	totalbytesread +=bytesread;
  8292 
  8293 	return totalbytesread;
  8294 }
  8295 
  8296 /*
  8297  * Function:
  8298  *
  8299  *   mp4_i32 readAVC1(MP4HandleImp handle,
  8300  *                    avcSampleEntry *avc1)
  8301  *
  8302  * Description:
  8303  *
  8304  *   This function parses one avc1 atom.
  8305  *
  8306  * Parameters:
  8307  *
  8308  *   handle             MP4 library handle
  8309  *   avc1               avc1 pointer
  8310  *
  8311  * Return value:
  8312  *
  8313  *   Negative integer   Error
  8314  *   >= 0               Success. Value tells how many bytes were read.
  8315  *
  8316  */
  8317 mp4_i32 readAVC1(MP4HandleImp handle, avcSampleEntry *avc1)
  8318 {
  8319   mp4_i32 bytesread;
  8320   mp4_i32 totalbytesread = 0;
  8321 
  8322   if ((avc1->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  8323     return -100;
  8324 
  8325   bytesread = readAtomHeader(handle, avc1->atomhdr);
  8326 
  8327   if (bytesread < 0)
  8328     return -1;
  8329   totalbytesread += bytesread;
  8330 
  8331   if (avc1->atomhdr->type != ATOMTYPE_AVC1)
  8332     return -1;
  8333 
  8334   bytesread = discardData(handle, 6);
  8335   if (bytesread < 0)
  8336     return -1;
  8337   totalbytesread += bytesread;
  8338 
  8339   bytesread = readData(handle, handle->buf, 2);
  8340   if (bytesread < 0)
  8341     return -1;
  8342   avc1->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
  8343   totalbytesread += bytesread;
  8344 
  8345   bytesread = discardData(handle, 16);
  8346   if (bytesread < 0)
  8347     return -1;
  8348   totalbytesread += bytesread;
  8349 
  8350   bytesread = readData(handle, handle->buf, 2);
  8351   if (bytesread < 0)
  8352     return -1;
  8353   avc1->width = u16endian(*((mp4_u16 *)handle->buf));
  8354   totalbytesread += bytesread;
  8355 
  8356   bytesread = readData(handle, handle->buf, 2);
  8357   if (bytesread < 0)
  8358     return -1;
  8359   avc1->height = u16endian(*((mp4_u16 *)handle->buf));
  8360   totalbytesread += bytesread;
  8361 
  8362   bytesread = discardData(handle, 50);
  8363   if (bytesread < 0)
  8364     return -1;
  8365   totalbytesread += bytesread;
  8366 
  8367   /* Check for the present atoms */
  8368   while ((mp4_u32)totalbytesread < avc1->atomhdr->size)
  8369   {
  8370     mp4_u32 type;
  8371 
  8372     if (peekData(handle, handle->buf, 8) < 0)
  8373       return -1;
  8374 
  8375     type = u32endian(*((mp4_u32 *)(handle->buf+4)));
  8376 
  8377     switch (type)
  8378     {
  8379     case ATOMTYPE_AVCC:
  8380 
  8381 		if (avc1->avcc) /* avcC has already been read, more than one is not allowed. */
  8382 			return -1;
  8383 
  8384 		if ((avc1->avcc = (avcConfigurationAtom *)mp4malloc(sizeof(avcConfigurationAtom))) == NULL)
  8385 			return -100;
  8386 
  8387 		bytesread = readAVCC(handle, avc1->avcc);  
  8388 		if(bytesread < 0)
  8389 			return -1;
  8390 		totalbytesread +=bytesread;
  8391   	    break;
  8392 
  8393     case ATOMTYPE_BTRT:
  8394 
  8395 		if (avc1->btrt) /* btrt has already been read, more than one is not allowed. */
  8396 			return -1;
  8397 
  8398 		if ((avc1->btrt = (mpeg4BitrateAtom *)mp4malloc(sizeof(mpeg4BitrateAtom))) == NULL)
  8399 			return -100;
  8400 
  8401 		bytesread = readBTRT(handle, avc1->btrt);  
  8402 		if(bytesread < 0)
  8403 			return -1;
  8404 		totalbytesread +=bytesread;
  8405 	    break;
  8406 
  8407     case ATOMTYPE_M4DS:
  8408 
  8409 		if (avc1->m4ds) /* m4ds has already been read, more than one is not allowed. */
  8410 			return -1;
  8411 
  8412 		if ((avc1->m4ds = (mpeg4ExtensionDescriptorsAtom *)mp4malloc(sizeof(mpeg4ExtensionDescriptorsAtom))) == NULL)
  8413 			return -100;
  8414 
  8415 		bytesread = readM4DS(handle, avc1->m4ds);  
  8416 		if(bytesread < 0)
  8417 			return -1;
  8418 		totalbytesread +=bytesread;
  8419 	    break;
  8420 	 
  8421 	 default:
  8422 
  8423         bytesread = readUnknown(handle);
  8424         if (bytesread < 0)
  8425             return -1;
  8426         totalbytesread += bytesread;
  8427 
  8428         break;
  8429 
  8430 	}
  8431   }
  8432 
  8433   return totalbytesread;
  8434 }
  8435 
  8436 /*
  8437  * Function:
  8438  *
  8439  *   mp4_i32 freeAVCC(avcConfigurationAtom *avcc)
  8440  *
  8441  * Description:
  8442  *
  8443  *   This function frees memory for avcc atom.
  8444  *
  8445  * Parameters:
  8446  *
  8447  *   avcc       avcc atom pointer
  8448  *
  8449  * Return value:
  8450  *
  8451  *   0          Success
  8452  *   Negative   Error
  8453  *
  8454  */
  8455 mp4_i32 freeAVCC(avcConfigurationAtom *avcc)
  8456 {
  8457   if (avcc)
  8458   {
  8459     if (freeAtomHeader(avcc->atomhdr) < 0)
  8460       return -1;
  8461 	if(avcc->avcConfig)
  8462 		mp4free(avcc->avcConfig);
  8463 
  8464     mp4free(avcc);
  8465   }
  8466 
  8467   return 0;
  8468 }
  8469 
  8470 /*
  8471  * Function:
  8472  *
  8473  *   mp4_i32 freeBTRT(mpeg4BitrateAtom *btrt)
  8474  *
  8475  * Description:
  8476  *
  8477  *   This function frees memory for btrt atom.
  8478  *
  8479  * Parameters:
  8480  *
  8481  *   btrt       btrt atom pointer
  8482  *
  8483  * Return value:
  8484  *
  8485  *   0          Success
  8486  *   Negative   Error
  8487  *
  8488  */
  8489 mp4_i32 freeBTRT(mpeg4BitrateAtom *btrt)
  8490 {
  8491   if (btrt)
  8492   {
  8493     if (freeAtomHeader(btrt->atomhdr) < 0)
  8494       return -1;
  8495 
  8496     mp4free(btrt);
  8497   }
  8498 
  8499   return 0;
  8500 }
  8501 
  8502 /*
  8503  * Function:
  8504  *
  8505  *   mp4_i32 freeM4DS(mpeg4ExtensionDescriptorsAtom *m4ds)
  8506  *
  8507  * Description:
  8508  *
  8509  *   This function frees memory for m4ds atom.
  8510  *
  8511  * Parameters:
  8512  *
  8513  *   m4ds       m4ds atom pointer
  8514  *
  8515  * Return value:
  8516  *
  8517  *   0          Success
  8518  *   Negative   Error
  8519  *
  8520  */
  8521 mp4_i32 freeM4DS(mpeg4ExtensionDescriptorsAtom *m4ds)
  8522 {
  8523   if (m4ds)
  8524   {
  8525     if (freeAtomHeader(m4ds->atomhdr) < 0)
  8526       return -1;
  8527 	if(m4ds->descr)
  8528 		mp4free(m4ds->descr);
  8529 
  8530     mp4free(m4ds);
  8531   }
  8532 
  8533   return 0;
  8534 }
  8535 
  8536 /*
  8537  * Function:
  8538  *
  8539  *   mp4_i32 freeAVC1(avcSampleEntry *avc1)
  8540  *
  8541  * Description:
  8542  *
  8543  *   This function frees memory for avc1 atom.
  8544  *
  8545  * Parameters:
  8546  *
  8547  *   avc1       avc1 atom pointer
  8548  *
  8549  * Return value:
  8550  *
  8551  *   0          Success
  8552  *   Negative   Error
  8553  *
  8554  */
  8555 mp4_i32 freeAVC1(avcSampleEntry *avc1)
  8556 {
  8557   if (avc1)
  8558   {
  8559     if (freeAtomHeader(avc1->atomhdr) < 0)
  8560       return -1;
  8561     if (freeAVCC(avc1->avcc) < 0)
  8562       return -1;
  8563 	if (freeBTRT(avc1->btrt) < 0)
  8564 		return -1;
  8565 	if (freeM4DS(avc1->m4ds) < 0)
  8566 		return -1;
  8567 
  8568     mp4free(avc1);
  8569   }
  8570 
  8571   return 0;
  8572 }
  8573 
  8574 /*
  8575  * Function:
  8576  *
  8577  *   mp4_i32 readSQCP(MP4HandleImp handle,
  8578  *                    qcelpSampleEntry *sqcp)
  8579  *
  8580  * Description:
  8581  *
  8582  *   This function parses one SQCP atom.
  8583  *
  8584  * Parameters:
  8585  *
  8586  *   handle             MP4 library handle
  8587  *   sqcp               SQCP pointer
  8588  *
  8589  * Return value:
  8590  *
  8591  *   Negative integer   Error
  8592  *   >= 0               Success. Value tells how many bytes were read.
  8593  *
  8594  */
  8595 mp4_i32 readSQCP(MP4HandleImp handle, qcelpSampleEntry *sqcp)
  8596 {
  8597   mp4_i32 bytesread;
  8598   mp4_i32 totalbytesread = 0;
  8599 
  8600 
  8601   if ((sqcp->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  8602     return -100;
  8603 
  8604   bytesread = readAtomHeader(handle, sqcp->atomhdr);
  8605   if (bytesread < 0)
  8606     return -1;
  8607   totalbytesread += bytesread;
  8608 
  8609   if (sqcp->atomhdr->type != ATOMTYPE_SQCP)
  8610     return -1;
  8611 
  8612 
  8613   bytesread = discardData(handle, 6);
  8614   if (bytesread < 0)
  8615     return -1;
  8616   totalbytesread += bytesread;
  8617 
  8618   bytesread = readData(handle, handle->buf, 2);
  8619   if (bytesread < 0)
  8620     return -1;
  8621   sqcp->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
  8622   totalbytesread += bytesread;
  8623 
  8624   bytesread = discardData(handle, 16);
  8625   if (bytesread < 0)
  8626     return -1;
  8627   totalbytesread += bytesread;
  8628 
  8629   bytesread = readData(handle, handle->buf, 2);
  8630   if (bytesread < 0)
  8631     return -1;
  8632   sqcp->timeScale = u16endian(*((mp4_u16 *)handle->buf));
  8633   totalbytesread += bytesread;
  8634 
  8635   bytesread = discardData(handle, 2);
  8636   if (bytesread < 0)
  8637     return -1;
  8638   totalbytesread += bytesread;
  8639 
  8640   if ((sqcp->dqcp = (qcelpDecSpecStruc *)mp4malloc(sizeof(qcelpDecSpecStruc))) == NULL)
  8641     return -100;
  8642 
  8643   bytesread = readDQCP(handle, sqcp->dqcp);
  8644   if (bytesread < 0)
  8645     return -1;
  8646   totalbytesread += bytesread;
  8647   
  8648   if ( totalbytesread < sqcp->atomhdr->size )
  8649   	{
  8650     bytesread = discardData(handle, sqcp->atomhdr->size - totalbytesread );
  8651   	if (bytesread < 0)
  8652   		{
  8653     	return -1;	  		
  8654   		}
  8655   	totalbytesread += bytesread;
  8656   	}  
  8657 
  8658   return totalbytesread;
  8659 }
  8660 
  8661 /*
  8662  * Function:
  8663  *
  8664  *   mp4_i32 freeSQCP(qcelpSampleEntry *sqcp)
  8665  *
  8666  * Description:
  8667  *
  8668  *   This function frees memory for SQCP atom.
  8669  *
  8670  * Parameters:
  8671  *
  8672  *   sqcp       SQCP atom pointer
  8673  *
  8674  * Return value:
  8675  *
  8676  *   0          Success
  8677  *   Negative   Error
  8678  *
  8679  */
  8680 mp4_i32 freeSQCP(qcelpSampleEntry *sqcp)
  8681 {
  8682   if (sqcp)
  8683   {
  8684     if (freeAtomHeader(sqcp->atomhdr) < 0)
  8685       return -1;
  8686     if (freeDQCP(sqcp->dqcp) < 0)
  8687       return -1;
  8688 
  8689     mp4free(sqcp);
  8690   }
  8691 
  8692   return 0;
  8693 }
  8694 
  8695 /*
  8696  * Function:
  8697  *
  8698  *   mp4_i32 readDQCP(MP4HandleImp handle,
  8699  *                    qcelpDecSpecStruc *dqcp)
  8700  *
  8701  * Description:
  8702  *
  8703  *   This function parses one DQCP atom.
  8704  *
  8705  * Parameters:
  8706  *
  8707  *   handle             MP4 library handle
  8708  *   dqcp               DQCP pointer
  8709  *
  8710  * Return value:
  8711  *
  8712  *   Negative integer   Error
  8713  *   >= 0               Success. Value tells how many bytes were read.
  8714  *
  8715  */
  8716 mp4_i32 readDQCP(MP4HandleImp handle, qcelpDecSpecStruc *dqcp)
  8717 {
  8718   mp4_i32 bytesread;
  8719   mp4_i32 totalbytesread = 0;
  8720 
  8721 
  8722   if ((dqcp->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  8723     return -100;
  8724 
  8725   bytesread = readAtomHeader(handle, dqcp->atomhdr);
  8726   if (bytesread < 0)
  8727     return -1;
  8728   totalbytesread += bytesread;
  8729 
  8730   if (dqcp->atomhdr->type != ATOMTYPE_DQCP)
  8731     return -1;
  8732 
  8733 
  8734   bytesread = readData(handle, handle->buf, 4);
  8735   if (bytesread < 0)
  8736     return -1;
  8737   dqcp->vendor = u32endian(*((mp4_u32 *)handle->buf));
  8738   totalbytesread += bytesread;
  8739 
  8740   bytesread = readData(handle, handle->buf, 1);
  8741   if (bytesread < 0)
  8742     return -1;
  8743   dqcp->decoderVersion = handle->buf[0];
  8744   totalbytesread += bytesread;
  8745 
  8746   bytesread = readData(handle, handle->buf, 1);
  8747   if (bytesread < 0)
  8748     return -1;
  8749   dqcp->framesPerSample = handle->buf[0];
  8750   totalbytesread += bytesread;
  8751 
  8752   return totalbytesread;
  8753 }
  8754 
  8755 /*
  8756  * Function:
  8757  *
  8758  *   mp4_i32 freeDQCP(qcelpDecSpecStruc *dqcp)
  8759  *
  8760  * Description:
  8761  *
  8762  *   This function frees memory for DQCP atom.
  8763  *
  8764  * Parameters:
  8765  *
  8766  *   damr       DQCP atom pointer
  8767  *
  8768  * Return value:
  8769  *
  8770  *   0          Success
  8771  *   Negative   Error
  8772  *
  8773  */
  8774 mp4_i32 freeDQCP(qcelpDecSpecStruc *dqcp)
  8775 {
  8776   if (dqcp)
  8777   {
  8778     if (freeAtomHeader(dqcp->atomhdr) < 0)
  8779       return -1;
  8780 
  8781     mp4free(dqcp);
  8782   }
  8783 
  8784   return 0;
  8785 }
  8786 
  8787 /*
  8788  * Function:
  8789  *
  8790  *   mp4_i32 readSDTP(MP4HandleImp handle, sampleDependencyAtom *sdtp, 
  8791  * 				      mp4_i32 sample_count)
  8792  *
  8793  * Description:
  8794  *
  8795  *   This function parses one SDTP atom.
  8796  *
  8797  * Parameters:
  8798  *
  8799  *   handle             MP4 library handle
  8800  *   sdtp               SDTP atom pointer
  8801  *
  8802  * Return value:
  8803  *
  8804  *   Negative integer   Error
  8805  *   >= 0               Success. Value tells how many bytes were read.
  8806  *
  8807  */
  8808 
  8809 mp4_i32 readSDTP(MP4HandleImp handle, 
  8810 				 sampleDependencyAtom *sdtp, 
  8811 				 mp4_i32 sample_count)
  8812 {
  8813   mp4_i32 bytesread = 0;
  8814   mp4_i32 totalbytesread = 0;
  8815   mp4_u32 i = 0;
  8816 
  8817   if ((sdtp->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  8818     return -100;
  8819 
  8820   bytesread = readAtomHeader(handle, sdtp->atomhdr);
  8821   if (bytesread < 0)
  8822     return -1;
  8823   totalbytesread += bytesread;
  8824 
  8825   if (sdtp->atomhdr->type != ATOMTYPE_SDTP)
  8826     return -1;
  8827   
  8828   bytesread = readData(handle, handle->buf, 1); //Version must be 0
  8829   if (bytesread < 0 || handle->buf[0] != 0)
  8830     return -1;
  8831   totalbytesread += bytesread;
  8832   bytesread = readData(handle, handle->buf, 3); // Flags must be 0
  8833   if (bytesread < 0 || handle->buf[0] != 0 || handle->buf[1] != 0 || handle->buf[2] != 0)
  8834     return -1;
  8835   totalbytesread += bytesread;
  8836 
  8837   // sample_count == (size_of_atom - 12) ???  12 = size + 'sdtp' + ver + flags = 4 + 4 + 1 + 3 ???
  8838   //
  8839   // sample_count is taken from the sample_count in the Sample Size Box ('stsz') or
  8840   // Compact Sample Size Box (‘stz2’).
  8841   if (sample_count != sdtp->atomhdr->size-12 || sample_count < 0)
  8842 	  {
  8843 	  // as each byte consititue one entry in the table, the number of remaining bytes in this
  8844 	  // atom should match the sample count.  If not, the file is corrupted.
  8845 	  return -1;
  8846 	  }
  8847   
  8848   if ((sdtp->dep = (sampleDependency *)mp4malloc(sample_count * sizeof(sampleDependency))) == NULL)
  8849     return -100;
  8850   
  8851   for(i=0;i<sample_count;i++)
  8852   {
  8853     bytesread = readData(handle, handle->buf, 1);
  8854     if (bytesread < 0)
  8855       return -1;
  8856     
  8857     sdtp->dep[i].sDependsOn = (handle->buf[0] >> 4) & 0x03; // value from 0 to 3
  8858     sdtp->dep[i].sIsDependentOn = (handle->buf[0] >> 2) & 0x03; // value from 0 to 3
  8859     sdtp->dep[i].sHasRedundancy = handle->buf[0] & 0x03; // value from 0 to 3
  8860     totalbytesread += bytesread;
  8861   }
  8862 
  8863   sdtp->sampleCount = sample_count;
  8864   return totalbytesread;	
  8865 }
  8866 
  8867 /*
  8868  * Function:
  8869  *
  8870  *   mp4_i32 readBoxHeader(MP4HandleImp handle, mp4_i64* size, mp4_u32* type)
  8871  * 				      
  8872  *
  8873  * Description:
  8874  *
  8875  *   This function parses the size and type information for a box. 
  8876  *   Taking into account largesize if needed.
  8877  *
  8878  * Parameters:
  8879  *
  8880  *   handle             MP4 library handle
  8881  *   size               Size of box is returned here
  8882  *   type               Type of the box is returned here
  8883  * Return value:
  8884  *
  8885  *   Negative integer   Error
  8886  *   0               Success.
  8887  *
  8888  */
  8889 mp4_i32 readBoxHeader(MP4HandleImp handle, mp4_i64* size, mp4_u32* type)
  8890 {
  8891   if (peekData(handle, handle->buf, 8) < 0)
  8892     return -1;
  8893 
  8894   *size = u32endian(*((mp4_u32 *)handle->buf));
  8895   *type = u32endian(*((mp4_u32 *)(handle->buf+4)));
  8896 
  8897   if (*size == 1)
  8898   {
  8899     if (peekData(handle, handle->buf, 16) < 0)
  8900       return -1;
  8901     
  8902     *size = u64endian(*((mp4_u64 *)(handle->buf+8)));
  8903   }
  8904 
  8905   return 0;
  8906 }
  8907 
  8908 /*
  8909  */
  8910 
  8911 mp4_i64 getChunkOffset(sampleTableAtom *stbl, mp4_u32 index)
  8912 {
  8913   if (stbl->is32BitOffsets)
  8914   	return (mp4_i64)stbl->stco->chunkOffset[index];
  8915   else
  8916     return stbl->stco64->chunkOffset[index];
  8917 }
  8918 
  8919 /*
  8920  * Function:
  8921  *
  8922  *   mp4_i32 readMeta(MP4HandleImp handle,
  8923  *                    metaAtom *meta)
  8924  *
  8925  * Description:
  8926  *
  8927  *   This function parses one META atom.
  8928  *
  8929  * Parameters:
  8930  *
  8931  *   handle             MP4 library handle
  8932  *   meta               META pointer
  8933  *
  8934  * Return value:
  8935  *
  8936  *   Negative integer   Error
  8937  *   >= 0               Success. Value tells how many bytes were read.
  8938  *
  8939  */
  8940 mp4_i32 readMeta(MP4HandleImp handle, metaAtom *meta)
  8941 {
  8942     mp4_i32 bytesread;
  8943     mp4_i32 totalbytesread = 0;
  8944 
  8945 
  8946     if ((meta->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  8947       return -100;
  8948 
  8949     bytesread = readFullAtomHeader(handle, meta->atomhdr);
  8950     if (bytesread < 0)
  8951       return -1;
  8952     totalbytesread += bytesread;
  8953 
  8954     if (meta->atomhdr->type != ATOMTYPE_META)
  8955       return -1;
  8956 
  8957 
  8958     while ((mp4_u32)totalbytesread < meta->atomhdr->size)
  8959     {
  8960       mp4_u32 type;
  8961 
  8962 
  8963       if (peekData(handle, handle->buf, 8) < 0)
  8964         return -1;
  8965       
  8966       type = u32endian(*((mp4_u32 *)(handle->buf+4)));
  8967 
  8968       switch (type)
  8969       {
  8970       case ATOMTYPE_HDLR:
  8971 
  8972         if (meta->hdlr) /* HDLR has already been read, more than one is not allowed */
  8973           return -1;
  8974 
  8975         if ((meta->hdlr = (handlerAtom *)mp4malloc(sizeof(handlerAtom))) == NULL)
  8976           return -100;
  8977 
  8978         bytesread = readHDLR(handle, meta->hdlr);
  8979         if (bytesread < 0)
  8980           return -1;
  8981         totalbytesread += bytesread;
  8982 
  8983         break;
  8984           
  8985       case ATOMTYPE_ID32:
  8986           
  8987         if (meta->ID32) /* ID32 has already been read, more than one is not allowed */
  8988           return -1;
  8989 
  8990         if ((meta->ID32 = (ID32Atom *)mp4malloc(sizeof(ID32Atom))) == NULL)
  8991           return -100;
  8992 
  8993         bytesread = readID32(handle, meta->ID32);
  8994         if (bytesread < 0)
  8995           return -1;
  8996         totalbytesread += bytesread;
  8997           
  8998         break;
  8999         
  9000       default:
  9001 
  9002         bytesread = readUnknown(handle);
  9003         if (bytesread < 0)
  9004           return -1;
  9005         totalbytesread += bytesread;
  9006 
  9007         break;
  9008       }
  9009     }
  9010 
  9011     return totalbytesread;
  9012 }
  9013 
  9014 /*
  9015  * Function:
  9016  *
  9017  *   mp4_i32 readID32(MP4HandleImp handle,
  9018  *                    ID32Atom *ID32)
  9019  *
  9020  * Description:
  9021  *
  9022  *   This function parses one ID32 atom.
  9023  *
  9024  * Parameters:
  9025  *
  9026  *   handle             MP4 library handle
  9027  *   ID32               ID32 pointer
  9028  *
  9029  * Return value:
  9030  *
  9031  *   Negative integer   Error
  9032  *   >= 0               Success. Value tells how many bytes were read.
  9033  *
  9034  */
  9035 mp4_i32 readID32(MP4HandleImp handle, ID32Atom *ID32)
  9036 {
  9037    mp4_i32 bytesread;
  9038    mp4_i32 totalbytesread = 0;
  9039 
  9040 
  9041    if ((ID32->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
  9042      return -100;
  9043 
  9044    bytesread = readFullAtomHeader(handle, ID32->atomhdr);
  9045    if (bytesread < 0)
  9046      return -1;
  9047    totalbytesread += bytesread;
  9048 
  9049    if (ID32->atomhdr->type != ATOMTYPE_ID32)
  9050      return -1;
  9051 
  9052    // next 2 bytes: top bit is padding, remaining 15 bits is Packed ISO-639-2/T language code 
  9053    bytesread = readData(handle, handle->buf, 2);
  9054    if (bytesread < 0)
  9055      return -1;
  9056    ID32->language = u16endian(*((mp4_u16 *)handle->buf));
  9057    totalbytesread += bytesread;
  9058    
  9059    if ( handle->file )
  9060        {
  9061        ID32->atomcontentloc = handle->diskReadBufStart + handle->diskReadBufPos;
  9062        }
  9063    else
  9064        {
  9065        ID32->atomcontentloc = handle->absPosition;
  9066        }
  9067    
  9068    bytesread = discardData(handle, ID32->atomhdr->size - totalbytesread );
  9069    if (bytesread < 0)
  9070      return -1;
  9071    totalbytesread += bytesread;     
  9072    
  9073    return totalbytesread;
  9074 }
  9075 
  9076 /*
  9077  * Function:
  9078  *
  9079  *   mp4_i32 freeMETA(metaAtom *meta)
  9080  *
  9081  * Description:
  9082  *
  9083  *   This function frees memory for META atom.
  9084  *
  9085  * Parameters:
  9086  *
  9087  *   meta       META atom pointer
  9088  *
  9089  * Return value:
  9090  *
  9091  *   0          Success
  9092  *   Negative   Error
  9093  *
  9094  */
  9095 mp4_i32 freeMETA(metaAtom *meta)
  9096 {
  9097   if (meta)
  9098   {
  9099     if (freeAtomHeader(meta->atomhdr) < 0)
  9100       return -1;
  9101     if (freeHDLR(meta->hdlr) < 0)
  9102        return -1;
  9103     if (freeID32(meta->ID32) < 0)
  9104       return -1;
  9105 
  9106     mp4free(meta);
  9107   }
  9108 
  9109   return 0;
  9110 }
  9111 
  9112 /*
  9113  * Function:
  9114  *
  9115  *   mp4_i32 freeID32(ID32Atom *ID32)
  9116  *
  9117  * Description:
  9118  *
  9119  *   This function frees memory for ID32 atom.
  9120  *
  9121  * Parameters:
  9122  *
  9123  *   ID32       ID32 atom pointer
  9124  *
  9125  * Return value:
  9126  *
  9127  *   0          Success
  9128  *   Negative   Error
  9129  *
  9130  */
  9131 mp4_i32 freeID32(ID32Atom *ID32)
  9132 {
  9133   if (ID32)
  9134   {
  9135     if (freeAtomHeader(ID32->atomhdr) < 0)
  9136       return -1;
  9137 
  9138     mp4free(ID32);
  9139   }
  9140 
  9141   return 0;
  9142 }
  9143 // End of File