diff -r 000000000000 -r bde4ae8d615e os/mm/mmplugins/lib3gp/impl/src/compose.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/mm/mmplugins/lib3gp/impl/src/compose.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,7464 @@ +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include <3gplibrary/mp4config.h> +#include <3gplibrary/mp4lib.h> +#include "mp4atom.h" +#include "mp4memwrap.h" +#include "mp4file.h" +#include "mp4endian.h" +#include "mp4compose.h" +#include "mp4currenttime.h" +#include "mp4utils.h" + +#define MP4_INT_MAX KMaxTInt32 +#define MDAT_HEADER_SIZE 16 + +// MACROS +// Debug print macro +#ifdef _DEBUG +#include <e32svr.h> +#define PRINT(x) +#else +#define PRINT(x) +#endif + + +inline void updateChunkOffset(sampleTable *st, mp4_i32 index, mp4_i64 value) +{ + if (value > MP4_INT_MAX) + st->stcoNeed64Bits = ETrue; + + st->stcoChunkOffset[index] = value; +} + +/* must be called after determineAudioTrakMetaDataSize and determineVideoTrakMetaDataSize */ +size_t mvhdAtomSize(MP4HandleImp handle) +{ + if (handle->videoDuration > MP4_INT_MAX || handle->audioDuration > MP4_INT_MAX) + { + return 120; + } + else + { + return 108; + } +} + + + +/* helper functions */ +mp4_i32 formatMdatHeader(mp4_u8 *buffer, mp4_i64 size); + +/* + * Function: + * + * mp4_i32 updateVideoMetaData(MP4HandleImp handle, + * mp4_u32 size, + * mp4_u32 duration) + * + * Description: + * + * This function updates sample table atom data. + * + * One call of this function will generate one chunk in the MP4 file. + * + * Parameters: + * + * handle MP4 library handle + * size Size of video frame to insert + * duration Duration of the video frame (in media timescale) + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 updateVideoMetaData(MP4HandleImp handle, mp4_u32 size, mp4_u32 duration, mp4_bool keyframe) +{ + if (handle->flags & MP4_FLAG_LONGCLIP) + { + if (handle->metaDataBlocks == BLOCK_LIMIT) + { + /* Write metadata to temporary files */ + + if (writeMetaDataTmp(handle) < 0) + return -1; + } + + handle->metaDataBlocks++; + } + + handle->videoSampleTable->currentChunk++; + + if (updateDecodingTimeToSample(handle, handle->videoSampleTable, duration) < 0) + return -1; + + if (updateSampleSize(handle, handle->videoSampleTable, size) < 0) + return -1; + + if (updateSampleToChunk(handle->videoSampleTable) < 0) + return -1; + + if (updateChunkOffset(handle, handle->videoSampleTable) < 0) + return -1; + + if (keyframe) + if (updateSyncSample(handle, handle->videoSampleTable) < 0) + return -1; + + return 0; +} + + +/* + * Function: + * + * mp4_i32 updateAudioMetaData(MP4HandleImp handle, + * mp4_u32 size, + * mp4_u32 numberofframes) + * + * Description: + * + * This function updates sample table atom data. + * + * One call of this function will generate one chunk in the MP4 file. + * + * Parameters: + * + * handle MP4 library handle + * size Size of video frame to insert + * duration Duration of audio frames (in timescale, + * see MP4ComposeAddAudioDescription) + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 updateAudioMetaData(MP4HandleImp handle, mp4_u32 size, mp4_u32 duration) +{ + if (handle->flags & MP4_FLAG_LONGCLIP) + { + if (handle->metaDataBlocks == BLOCK_LIMIT) + { + /* Write metadata to temporary files */ + + if (writeMetaDataTmp(handle) < 0) + return -1; + } + + handle->metaDataBlocks++; + } + + handle->audioSampleTable->currentChunk++; + + if (updateDecodingTimeToSample(handle, handle->audioSampleTable, duration) < 0) + return -1; + + if (updateSampleSize(handle, handle->audioSampleTable, size) < 0) + return -1; + + if (updateSampleToChunk(handle->audioSampleTable) < 0) + return -1; + + if (updateChunkOffset(handle, handle->audioSampleTable) < 0) + return -1; + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeFTYPAndMDATToFile(MP4HandleImp handle) + * + * Description: + * + * This function writes FTYP box to a file. In addition, it writes MDAT box + * size and type to a file. The function is used when meta data is put to + * the end of file. + * + * Parameters: + * + * handle MP4 library handle + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeFTYPAndMDATToFile(MP4HandleImp handle) +{ + mp4_u8 buf[32]; + mp4_u32 i = 0; + + + if (writeFTYP(handle) < 0) + return -1; + + handle->ftypWritten = MP4TRUE; + + + i = formatMdatHeader(buf, (mp4_u32)0); + if (writeFile(handle, buf, i) < 0) + return -1; + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeDataToFile(MP4HandleImp handle) + * + * Description: + * + * This function writes meta and media data to a file. + * + * Parameters: + * + * handle MP4 library handle + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeDataToFile(MP4HandleImp handle) +{ + PRINT((_L("e_writedatatofile 1"))); + mp4_u32 metaDataSize = 0; + trakSize *audioTrackSize; + trakSize *videoTrackSize; + mp4_bool haveAudio = MP4FALSE; + mp4_bool haveVideo = MP4FALSE; + mp4_u8 ftypdelta = 0; + + + if ((handle->type & MP4_TYPE_AMR_NB) || + (handle->type & MP4_TYPE_AMR_WB) || + (handle->type & MP4_TYPE_QCELP_13K) || + (handle->type & MP4_TYPE_MPEG4_AUDIO)) + haveAudio = MP4TRUE; + + if ((handle->type & MP4_TYPE_H263_PROFILE_0) || + (handle->type & MP4_TYPE_H263_PROFILE_3) || + (handle->type & MP4_TYPE_MPEG4_VIDEO) || + containsAvcVideo( handle->type ) ) + haveVideo = MP4TRUE; + + if ((handle->generate3G2 && !(handle->type & MP4_TYPE_QCELP_13K)) || + (!handle->generate3G2 && !(handle->type & MP4_TYPE_AMR_WB))) + ftypdelta = 4; /* one more additional compatible brand */ + else + ftypdelta = 0; + + if( containsAvcVideo( handle->type ) ) + { + ftypdelta += 4; + } + + PRINT((_L("e_writedatatofile_alloc_audiotrk 1"))); + audioTrackSize = (trakSize *)mp4malloc(sizeof(trakSize)); + if (audioTrackSize == NULL) + return -1; + PRINT((_L("e_writedatatofile_alloc_audiotrk 0"))); + + PRINT((_L("e_writedatatofile_alloc_videotrk 1"))); + videoTrackSize = (trakSize *)mp4malloc(sizeof(trakSize)); + if (videoTrackSize == NULL) + { + mp4free(audioTrackSize); + + return -1; + } + PRINT((_L("e_writedatatofile_alloc_videotrk 0"))); + + if (haveAudio) + { + PRINT((_L("e_writedatatofile_deter_audiotrk_metadatasize 1"))); + if (determineAudioTrakMetaDataSize(handle, handle->audioSampleTable, audioTrackSize) < 0) + { + mp4free(audioTrackSize); + mp4free(videoTrackSize); + return -1; + } + PRINT((_L("e_writedatatofile_deter_audiotrk_metadatasize 0"))); + } + + if (haveVideo) + { + PRINT((_L("e_writedatatofile_deter_videotrk_metadatasize 1"))); + if (determineVideoTrakMetaDataSize(handle, handle->videoSampleTable, videoTrackSize) < 0) + { + mp4free(audioTrackSize); + mp4free(videoTrackSize); + return -1; + } +PRINT((_L("e_writedatatofile_deter_videotrk_metadatasize 0"))); + } + + if (handle->flags & MP4_FLAG_METADATALAST) + { + metaDataSize += (FTYP_SIZE + ftypdelta); /* ftyp */ + handle->metaDataSize = metaDataSize; + } + else + { + metaDataSize += (FTYP_SIZE + ftypdelta); /* ftyp */ + metaDataSize += 8; /* moov atomheader */ + metaDataSize += mvhdAtomSize(handle); /* mvhd */ + if (handle->moovUDTA) + { + metaDataSize += 8 + (mp4_u32)handle->moovUDTA->atomcontentsize; + } + metaDataSize += audioTrackSize->trak; /* Audio trak */ + metaDataSize += videoTrackSize->trak; /* Video trak */ + + handle->metaDataSize = metaDataSize; + } + + + if (!(handle->flags & MP4_FLAG_LONGCLIP)) + { + /* Update metadata pointers only if metadata is in memory */ + + if (haveAudio) + { + PRINT((_L("e_writedatatofile_reupdata_audiometadata 1"))); + if (reUpdateAudioMetaData(handle->audioSampleTable, metaDataSize) < 0) + { + mp4free(audioTrackSize); + mp4free(videoTrackSize); + + return -1; + } + PRINT((_L("e_writedatatofile_reupdata_audiometadata 0"))); + } + + if (haveVideo) + { + PRINT((_L("e_writedatatofile_reupdata_videometadata 1"))); + if (reUpdateVideoMetaData(handle->videoSampleTable, metaDataSize) < 0) + { + mp4free(audioTrackSize); + mp4free(videoTrackSize); + + return -1; + } + PRINT((_L("e_writedatatofile_reupdata_videometadata 0"))); + } + } + else + { + /* Write the rest of metadata to temporary files */ + PRINT((_L("e_writedatatofile_write_metadatablocks 1"))); + if (handle->metaDataBlocks) + if (writeMetaDataTmp(handle) < 0) + { + mp4free(audioTrackSize); + mp4free(videoTrackSize); + return -1; + } + PRINT((_L("e_writedatatofile_write_metadatablocks 0"))); + } + + + if (handle->flags & MP4_FLAG_METADATALAST) + { + mp4_u8 buf[16]; + mp4_u32 moovSize = 0; + + moovSize += 8; /* moov atomheader */ + moovSize += mvhdAtomSize(handle); /* mvhd */ + moovSize += audioTrackSize->trak; /* Audio trak */ + moovSize += videoTrackSize->trak; /* Video trak */ + if (handle->moovUDTA) + { + moovSize += 8 + handle->moovUDTA->atomcontentsize; + } + + PRINT((_L("e_writedatatofile_write_moov 1"))); + if (writeMOOV(handle, moovSize, haveAudio, haveVideo, audioTrackSize, videoTrackSize) < 0) + { + mp4free(audioTrackSize); + mp4free(videoTrackSize); + + return -1; + } + PRINT((_L("e_writedatatofile_write_moov 0"))); + + /* Overwrite media data size */ + PRINT((_L("e_writedatatofile_update_moov_media_size 1"))); + if(!handle->bufferWrite) + { + if (seekFileAbsWrite(handle, (FTYP_SIZE + ftypdelta)) != 0) + { + mp4free(audioTrackSize); + mp4free(videoTrackSize); + return -1; + } + } + + //make sure the buf is large enough to hold the mdat header + TInt i; + i = formatMdatHeader(buf, handle->mediaDataBytes); + if (writeFileUnbuffered(handle, buf, i) < 0) + { + mp4free(audioTrackSize); + mp4free(videoTrackSize); + return -1; + } + PRINT((_L("e_writedatatofile_update_moov_media_size 0"))); + } + else + { + PRINT((_L("e_writedatatofile_write_ftyp 1"))); + if (writeFTYP(handle) < 0) + { + mp4free(audioTrackSize); + mp4free(videoTrackSize); + + return -1; + } + PRINT((_L("e_writedatatofile_write_ftyp 0"))); + + PRINT((_L("e_writedatatofile_write_new_moov 1"))); + if (writeMOOV(handle, metaDataSize - (FTYP_SIZE + ftypdelta), haveAudio, haveVideo, audioTrackSize, videoTrackSize) < 0) + { + mp4free(audioTrackSize); + mp4free(videoTrackSize); + + return -1; + } + PRINT((_L("e_writedatatofile_write_new_moov 0"))); + + PRINT((_L("e_writedatatofile_write_new_mdia 1"))); + if (writeMediaData(handle) < 0) + { + mp4free(audioTrackSize); + mp4free(videoTrackSize); + + return -1; + } + PRINT((_L("e_writedatatofile_write_new_mdia 0"))); + } + +PRINT((_L("e_writedatatofile_free_audioandvideotrks 1"))); + mp4free(audioTrackSize); + mp4free(videoTrackSize); +PRINT((_L("e_writedatatofile_free_audioandvideotrks 0"))); +PRINT((_L("e_writedatatofile 0"))); + return 0; +} + + +/* + * Function: + * + * mp4_i32 updateDecodingTimeToSample(MP4HandleImp handle, + * sampleTable *st, + * mp4_u32 duration) + * + * Description: + * + * This function updates stts atom data. + * + * Parameters: + * + * handle MP4 library handle + * st sampleTable + * duration Duration of sample to insert (in media timescale) + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 updateDecodingTimeToSample(MP4HandleImp handle, sampleTable *st, mp4_u32 duration) +{ + if (!handle) + return -1; + + if (handle->flags & MP4_FLAG_LONGCLIP) + { + if (st->sttsCurrentEntryCount == 0) + { + st->sttsSampleCount[st->sttsCurrentEntryCount] = 1; + st->sttsSampleDelta[st->sttsCurrentEntryCount] = duration; + + st->sttsCurrentEntryCount++; + st->sttsEntryCount++; + + return 0; + } + + if (st->sttsCurrentEntryCount == st->sttsMaxEntryCount) + { + void *p; + + p = mp4realloc(st->sttsSampleCount, + 2 * sizeof(mp4_u32) * st->sttsMaxEntryCount, + sizeof(mp4_u32) * st->sttsMaxEntryCount); + if (p == NULL) + return -1; + + st->sttsSampleCount = (mp4_u32 *)p; + + p = mp4realloc(st->sttsSampleDelta, + 2 * sizeof(mp4_u32) * st->sttsMaxEntryCount, + sizeof(mp4_u32) * st->sttsMaxEntryCount); + if (p == NULL) + return -1; + + st->sttsSampleDelta = (mp4_u32 *)p; + + st->sttsMaxEntryCount *= 2; + } + + if (st->sttsSampleDelta[st->sttsCurrentEntryCount - 1] == duration) + { + st->sttsSampleCount[st->sttsCurrentEntryCount - 1]++; + } + else + { + st->sttsSampleCount[st->sttsCurrentEntryCount] = 1; + st->sttsSampleDelta[st->sttsCurrentEntryCount] = duration; + + st->sttsCurrentEntryCount++; + st->sttsEntryCount++; + } + } + else + { + if (st->sttsEntryCount == 0) + { + st->sttsSampleCount[st->sttsEntryCount]++; + st->sttsSampleDelta[st->sttsEntryCount] = duration; + + st->sttsEntryCount++; + + return 0; + } + + if (st->sttsEntryCount == st->sttsMaxEntryCount) + { + void *p; + + p = mp4realloc(st->sttsSampleCount, + 2 * sizeof(mp4_u32) * st->sttsMaxEntryCount, + sizeof(mp4_u32) * st->sttsMaxEntryCount); + if (p == NULL) + return -1; + + st->sttsSampleCount = (mp4_u32 *)p; + + p = mp4realloc(st->sttsSampleDelta, + 2 * sizeof(mp4_u32) * st->sttsMaxEntryCount, + sizeof(mp4_u32) * st->sttsMaxEntryCount); + if (p == NULL) + return -1; + + st->sttsSampleDelta = (mp4_u32 *)p; + + st->sttsMaxEntryCount *= 2; + } + + if (st->sttsSampleDelta[st->sttsEntryCount - 1] == duration) + { + st->sttsSampleCount[st->sttsEntryCount - 1]++; + } + else + { + st->sttsSampleCount[st->sttsEntryCount] = 1; + st->sttsSampleDelta[st->sttsEntryCount] = duration; + + st->sttsEntryCount++; + } + } + + + return 0; +} + + +/* + * Function: + * + * mp4_i32 updateSampleSize(MP4HandleImp handle, + * sampleTable *st, + * mp4_u32 size) + * + * Description: + * + * This function updates stsz atom data. + * + * Parameters: + * + * handle MP4 library handle + * st sampleTable + * size Size of sample in bytes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 updateSampleSize(MP4HandleImp handle, sampleTable *st, mp4_u32 size) +{ + if (!handle) + return -1; + + if (size == 0) + return -1; + + if (handle->flags & MP4_FLAG_LONGCLIP) + { + if (st->stszCurrentSampleCount == st->stszMaxSampleCount) + { + void *p; + + p = mp4realloc(st->stszEntrySize, + 2 * sizeof(mp4_u32) * st->stszMaxSampleCount, + sizeof(mp4_u32) * st->stszMaxSampleCount); + if (p == NULL) + return -1; + + st->stszEntrySize = (mp4_u32 *)p; + + st->stszMaxSampleCount *= 2; + } + + st->stszEntrySize[st->stszCurrentSampleCount] = size; + + st->stszCurrentSampleCount++; + st->stszSampleCount++; + } + else + { + if (st->stszSampleCount == st->stszMaxSampleCount) + { + void *p; + + p = mp4realloc(st->stszEntrySize, + 2 * sizeof(mp4_u32) * st->stszMaxSampleCount, + sizeof(mp4_u32) * st->stszMaxSampleCount); + if (p == NULL) + return -1; + + st->stszEntrySize = (mp4_u32 *)p; + + st->stszMaxSampleCount *= 2; + } + + st->stszEntrySize[st->stszSampleCount] = size; + + st->stszSampleCount++; + } + + + return 0; +} + + +/* + * Function: + * + * mp4_i32 updateSampleToChunk(sampleTable *st) + * + * Description: + * + * This function updates stsc atom data. + * + * Parameters: + * + * st sampleTable + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 updateSampleToChunk(sampleTable *st) +{ + if (st->stscEntryCount != 0) + return 0; + + + st->stscFirstChunk[st->stscEntryCount] = st->currentChunk; + st->stscSamplesPerChunk[st->stscEntryCount] = 1; + st->stscSampleDescriptionIndex[st->stscEntryCount] = 1; /* Note: Need to update here for multiple sample entry support */ + st->stscEntryCount++; + + return 0; +} + + +/* + * Function: + * + * mp4_i32 updateChunkOffset(MP4HandleImp handle, + * sampleTable *st) + * + * Description: + * + * This function updates stco atom data. + * + * Parameters: + * + * handle MP4 library handle + * st sampleTable + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 updateChunkOffset(MP4HandleImp handle, sampleTable *st) +{ + if (handle->flags & MP4_FLAG_LONGCLIP) + { + if (st->stcoCurrentEntryCount == st->stcoMaxEntryCount) + { + void *p; + + p = mp4realloc(st->stcoChunkOffset, + 2 * sizeof(mp4_u64) * st->stcoMaxEntryCount, + sizeof(mp4_u64) * st->stcoMaxEntryCount); + if (p == NULL) + return -1; + + st->stcoChunkOffset = (mp4_u64*)p; + + st->stcoMaxEntryCount *= 2; + } + + if (handle->flags & MP4_FLAG_METADATALAST) + updateChunkOffset(st, st->stcoCurrentEntryCount, handle->mediaDataBytes); + else + updateChunkOffset(st, st->stcoCurrentEntryCount, handle->bytesInTmpFile); + + st->stcoCurrentEntryCount++; + st->stcoEntryCount++; + } + else + { + if (st->stcoEntryCount == st->stcoMaxEntryCount) + { + void *p; + + p = mp4realloc(st->stcoChunkOffset, + 2 * sizeof(mp4_u64) * st->stcoMaxEntryCount, + sizeof(mp4_u64) * st->stcoMaxEntryCount); + if (p == NULL) + return -1; + + st->stcoChunkOffset = (mp4_u64 *)p; + + st->stcoMaxEntryCount *= 2; + } + + if (handle->flags & MP4_FLAG_METADATALAST) + updateChunkOffset(st, st->stcoEntryCount, handle->mediaDataBytes); + else + updateChunkOffset(st, st->stcoEntryCount, handle->bytesInTmpFile); + + st->stcoEntryCount++; + } + + + return 0; +} + + +/* + * Function: + * + * mp4_i32 updateSyncSample(MP4HandleImp handle, + * sampleTable *st) + * + * Description: + * + * This function updates stss atom data. + * + * Parameters: + * + * handle MP4 library handle + * st sampleTable + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 updateSyncSample(MP4HandleImp handle, sampleTable *st) +{ + if (handle->flags & MP4_FLAG_LONGCLIP) + { + if (st->stssCurrentEntryCount == st->stssMaxEntryCount) + { + void *p; + + p = mp4realloc(st->stssSampleNumber, + 2 * sizeof(mp4_u32) * st->stssMaxEntryCount, + sizeof(mp4_u32) * st->stssMaxEntryCount); + if (p == NULL) + return -1; + + st->stssSampleNumber = (mp4_u32 *)p; + + st->stssMaxEntryCount *= 2; + } + + st->stssSampleNumber[st->stssCurrentEntryCount] = handle->videoSampleNum; + st->stssCurrentEntryCount++; + st->stssEntryCount++; + } + else + { + if (st->stssEntryCount == st->stssMaxEntryCount) + { + void *p; + + p = mp4realloc(st->stssSampleNumber, + 2 * sizeof(mp4_u32) * st->stssMaxEntryCount, + sizeof(mp4_u32) * st->stssMaxEntryCount); + if (p == NULL) + return -1; + + st->stssSampleNumber = (mp4_u32 *)p; + + st->stssMaxEntryCount *= 2; + } + + st->stssSampleNumber[st->stssEntryCount] = handle->videoSampleNum; + st->stssEntryCount++; + } + + + return 0; +} + + +/* + * Function: + * + * mp4_i32 determineAudioTrakMetaDataSize(MP4HandleImp handle, + * sampleTable *st, + * trakSize *ts) + * + * Description: + * + * This function calculates the audio track meta data size. + * + * Parameters: + * + * handle MP4 library handle + * st Sample table data + * ts Atom sizes are returned here + * + * Return value: + * + * 0 Success + * + */ +mp4_i32 determineAudioTrakMetaDataSize(MP4HandleImp handle, sampleTable *st, trakSize *ts) +{ + if (handle->type & MP4_TYPE_AMR_NB) /* AMR-NB */ + { + ts->damr = 17; + ts->samr = 36 + ts->damr; + ts->stsd = 16 + ts->samr; + } + else if (handle->type & MP4_TYPE_AMR_WB) /* AMR-WB */ + { + ts->damr = 17; + ts->sawb = 36 + ts->damr; + ts->stsd = 16 + ts->sawb; + } + else if ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio)) /* QCELP 13K stored in QCELPSampleEntry */ + { + ts->dqcp = 14; + ts->sqcp = 36 + ts->dqcp; + ts->stsd = 16 + ts->sqcp; + } + else if ((handle->type & MP4_TYPE_QCELP_13K) && (handle->qcelpStoredAsMPEGAudio)) /* QCELP 13K stored in MP4AudioDescription */ + { + calculateES_DescriptorSize(handle, MP4_TYPE_QCELP_13K); + ts->esds = 12 + handle->ES_DescriptorSize; /*37 + handle->audioDecSpecificInfoSize;*/ + ts->mp4a = 36 + ts->esds; + ts->stsd = 16 + ts->mp4a; + } + else /* MPEG audio */ + { + calculateES_DescriptorSize(handle, MP4_TYPE_MPEG4_AUDIO); + ts->esds = 12 + handle->ES_DescriptorSize; /*37 + handle->audioDecSpecificInfoSize;*/ + ts->mp4a = 36 + ts->esds; + ts->stsd = 16 + ts->mp4a; + } + ts->stts = 16 + st->sttsEntryCount * 8; + ts->stsc = 16 + st->stscEntryCount * 12; + if (st->stszSampleSize != 0) + ts->stsz = 20; + else + ts->stsz = 20 + st->stszSampleCount * 4; + ts->stco = 16 + st->stcoEntryCount * (st->stcoNeed64Bits ? 8 : 4); + ts->stbl = 8 + ts->stsd + ts->stts + ts->stsc + ts->stsz + ts->stco; + ts->dref = 28; + ts->dinf = 8 + ts->dref; + ts->smhd = 16; + ts->minf = 8 + ts->smhd + ts->dinf + ts->stbl; + ts->hdlr = 33; + + if (handle->audioDuration > MP4_INT_MAX) + { + ts->mdhd = 44; + ts->tkhd = 104; + } + else + { + ts->mdhd = 32; + ts->tkhd = 92; + } + + ts->mdia = 8 + ts->mdhd + ts->hdlr + ts->minf; + if ( handle->audioUDTA ) + { + ts->udta = 8 + handle->audioUDTA->atomcontentsize; + } + ts->trak = 8 + ts->tkhd + ts->mdia + ts->udta; + + return 0; +} + + +/* + * Function: + * + * mp4_i32 determineVideoTrakMetaDataSize(MP4HandleImp handle, + * sampleTable *st, + * trakSize *ts) + * + * Description: + * + * This function calculates the video track meta data size. + * + * Parameters: + * + * handle MP4 library handle + * st Sample table data + * ts Atom sizes are returned here + * + * Return value: + * + * 0 Success + * + */ +mp4_i32 determineVideoTrakMetaDataSize(MP4HandleImp handle, sampleTable *st, trakSize *ts) +{ + /* Note: This functions assumes single sample entry per media track. + If necessary, modify to support multiple sample entries in the future. */ + if ((handle->type & MP4_TYPE_H263_PROFILE_0) || (handle->type & MP4_TYPE_H263_PROFILE_3)) + { + ts->d263 = 15; + ts->s263 = 86 + ts->d263; + ts->stsd = 16 + ts->s263; + } + else /* MPEG-4 */ + if ((handle->type & MP4_TYPE_MPEG4_VIDEO)) + { + ts->esds = 37 + handle->videoDecSpecificInfoSize; + ts->mp4v = 86 + ts->esds; + ts->stsd = 16 + ts->mp4v; + } + else /* AVC */ + if ( containsAvcVideo( handle->type ) ) + { + /* Note: If necessary, add btrt and m4ds boxes here in the future. */ + ts->avcc = 8 + handle->videoDecSpecificInfoSize; /*handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfigSize;*/ + ts->avc1 = 86 + ts->avcc; + ts->stsd = 16 + ts->avc1; + } + else + { + } + + ts->stts = 16 + st->sttsEntryCount * 8; + ts->stsc = 16 + st->stscEntryCount * 12; + if (st->stszSampleSize != 0) + ts->stsz = 20; + else + ts->stsz = 20 + st->stszSampleCount * 4; + ts->stco = 16 + st->stcoEntryCount * (st->stcoNeed64Bits ? 8 : 4); + ts->stss = 16 + st->stssEntryCount * 4; + if( handle->videoSampleTable->sdtpEntryCount ) + ts->sdtp = 4 + 4 + 1 + 3 + handle->videoSampleTable->sdtpEntryCount; //size + 'SDTP' + ver + flags + dependencies + else + ts->sdtp = 0; + + ts->stbl = 8 + ts->stsd + ts->stts + ts->stsc + ts->stsz + ts->stco + ts->stss + ts->sdtp; + ts->dref = 28; + ts->dinf = 8 + ts->dref; + ts->vmhd = 20; + ts->minf = 8 + ts->vmhd + ts->dinf + ts->stbl; + ts->hdlr = 33; + + if (handle->videoDuration > MP4_INT_MAX) + { + ts->mdhd = 44; + ts->tkhd = 104; + } + else + { + ts->mdhd = 32; + ts->tkhd = 92; + } + + ts->mdia = 8 + ts->mdhd + ts->hdlr + ts->minf; + if ( handle->videoUDTA ) + { + ts->udta = 8 + handle->videoUDTA->atomcontentsize; + } + ts->trak = 8 + ts->tkhd + ts->mdia + ts->udta; + + return 0; +} + + +/* + * Function: + * + * mp4_i32 reUpdateAudioMetaData(sampleTable *st, + * mp4_u32 metaDataSize) + * + * Description: + * + * This function updates the chunk offsets in the meta data to point to + * correct places. + * + * Parameters: + * + * st Sample table data + * metaDataSize Meta data size + * + * Return value: + * + * 0 Success + * + */ +mp4_i32 reUpdateAudioMetaData(sampleTable *st, mp4_u32 metaDataSize) +{ + mp4_u32 i; + + + for (i = 0; i < st->stcoEntryCount; i++) + updateChunkOffset(st, i, st->stcoChunkOffset[i] + metaDataSize + MDAT_HEADER_SIZE); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 reUpdateVideoMetaData(sampleTable *st, + * mp4_u32 metaDataSize) + * + * Description: + * + * This function updates the chunk offsets in the meta data to point to + * correct places. + * + * Parameters: + * + * st Sample table data + * metaDataSize Meta data size + * + * Return value: + * + * 0 Success + * + */ +mp4_i32 reUpdateVideoMetaData(sampleTable *st, mp4_u32 metaDataSize) +{ + mp4_u32 i; + + + for (i = 0; i < st->stcoEntryCount; i++) + updateChunkOffset(st, i, st->stcoChunkOffset[i] + metaDataSize + MDAT_HEADER_SIZE); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeFTYP(MP4HandleImp handle) + * + * Description: + * + * Write FTYP atom. + * + * Parameters: + * + * handle MP4 library handle + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeFTYP(MP4HandleImp handle) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u8 ftypdelta = 0; + + if ((handle->generate3G2 && !(handle->type & MP4_TYPE_QCELP_13K)) || + (!handle->generate3G2 && !(handle->type & MP4_TYPE_AMR_WB))) + ftypdelta = 4; /* one more additional compatible brand */ + else + ftypdelta = 0; + + if( containsAvcVideo( handle->type ) ) + { + ftypdelta += 4; + } + if(handle->bufferWrite) + handle->ftypdelta=ftypdelta; + + buf = (mp4_u8 *)mp4malloc(FTYP_SIZE + ftypdelta); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)(FTYP_SIZE + ftypdelta)); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_FTYP); + i += 4; + + if ( containsAvcVideo( handle->type ) ) + { + if(handle->generateMP4) + { + /* MPEG-4 Major brand */ + buf[i++] = 'm'; + buf[i++] = 'p'; + buf[i++] = '4'; + buf[i++] = '2'; + } + + else + { + /* AVC is included for 3GPP Release 6 and beyond */ + /* Major brand */ + buf[i++] = '3'; + buf[i++] = 'g'; + buf[i++] = 'p'; + buf[i++] = '6'; + } + } + else + { + if(handle->generateMP4) + { + /* MPEG-4 Major brand */ + buf[i++] = 'm'; + buf[i++] = 'p'; + buf[i++] = '4'; + buf[i++] = '2'; + } + else if(handle->generate3G2) + { + /* 3GPP2 Major brand */ + buf[i++] = '3'; + buf[i++] = 'g'; + buf[i++] = '2'; + buf[i++] = 'a'; + } + else + { + /* 3GPP Major brand */ + buf[i++] = '3'; + buf[i++] = 'g'; + buf[i++] = 'p'; + buf[i++] = '4'; + } + } + + /* Minor version */ + if(handle->generateMP4) + { /* MPEG-4 Minor Version */ + insertu32(buf+i, (mp4_u32)(0)); /* 0 */ + i += 4; + } + else if(handle->generate3G2) + { /* 3GPP2 Minor Version */ + if( containsAvcVideo( handle->type ) ) + { + insertu32(buf+i, (mp4_u32)(2*256*256)); /* VB.0.0 */ + i += 4; + } + else + { + insertu32(buf+i, (mp4_u32)(1*256*256)); /* VA.0.0 */ + i += 4; + } + } + else + { /* 3GPP Minor Version */ + if( containsAvcVideo( handle->type ) ) + { + insertu32(buf+i, (mp4_u32)2*256); /* V6.3.0 */ + i += 4; + } + else + { + insertu32(buf+i, (mp4_u32)4*256); /* V4.4.0 */ + i += 4; + } + } + + /* Compatible brands */ + if(handle->generateMP4) + {/* MPEG-4 Compatible Brands */ + buf[i++] = 'm'; + buf[i++] = 'p'; + buf[i++] = '4'; + buf[i++] = '2'; + + buf[i++] = '3'; + buf[i++] = 'g'; + buf[i++] = 'p'; + buf[i++] = '4'; + + buf[i++] = 'i'; + buf[i++] = 's'; + buf[i++] = 'o'; + buf[i++] = 'm'; + if ( containsAvcVideo( handle->type ) ) + { + /* AVC is included for 3GPP Release 6 and beyond */ + buf[i++] = 'a'; + buf[i++] = 'v'; + buf[i++] = 'c'; + buf[i++] = '1'; + } + } + else if(handle->generate3G2) + {/* 3GPP2 Compatible Brands */ + if( containsAvcVideo( handle->type ) ) + { + buf[i++] = '3'; + buf[i++] = 'g'; + buf[i++] = '2'; + buf[i++] = 'b'; + if (!(handle->type & MP4_TYPE_QCELP_13K)) + { // If 3GPP codecs are used, then put 3GP6 in compatible brands + buf[i++] = '3'; + buf[i++] = 'g'; + buf[i++] = 'p'; + buf[i++] = '6'; + } + } + else + { + buf[i++] = '3'; + buf[i++] = 'g'; + buf[i++] = '2'; + buf[i++] = 'a'; + if (!(handle->type & MP4_TYPE_QCELP_13K)) + { // If 3GPP codecs are used, then put 3GP4 in compatible brands + buf[i++] = '3'; + buf[i++] = 'g'; + buf[i++] = 'p'; + buf[i++] = '4'; + } + } + if ( containsAvcVideo( handle->type ) ) + { + /* AVC is included for 3GPP Release 6 and beyond */ + buf[i++] = 'a'; + buf[i++] = 'v'; + buf[i++] = 'c'; + buf[i++] = '1'; + } + + buf[i++] = 'i'; + buf[i++] = 's'; + buf[i++] = 'o'; + buf[i++] = 'm'; + } + else + {/* 3GPP Compatible Brands */ + if ( containsAvcVideo( handle->type ) ) + { + buf[i++] = '3'; + buf[i++] = 'g'; + buf[i++] = 'p'; + buf[i++] = '6'; + } + else + { + buf[i++] = '3'; + buf[i++] = 'g'; + buf[i++] = 'p'; + buf[i++] = '4'; + } + + if (!(handle->type & MP4_TYPE_AMR_WB)) + { // If 3GPP2 codecs are used, then put 3G2A in compatible brands + buf[i++] = '3'; + buf[i++] = 'g'; + buf[i++] = '2'; + buf[i++] = 'a'; + } + + buf[i++] = 'i'; + buf[i++] = 's'; + buf[i++] = 'o'; + buf[i++] = 'm'; + + if ( containsAvcVideo( handle->type ) ) + { + /* AVC is included for 3GPP Release 6 and beyond */ + buf[i++] = 'a'; + buf[i++] = 'v'; + buf[i++] = 'c'; + buf[i++] = '1'; + } + + } + if (writeFile(handle, buf, (FTYP_SIZE + ftypdelta)) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeMOOV(MP4HandleImp handle, + * mp4_u32 moovSize, + * mp4_bool haveAudio, + * mp4_bool haveVideo, + * trakSize *audioTrackSize, + * trakSize *videoTrackSize) + * + * Description: + * + * Write MOOV atom. + * + * Parameters: + * + * handle MP4 library handle + * moovSize Size of MOOV atom in bytes + * haveAudio Flag to indicate whether audio exists or not + * haveVideo Flag to indicate whether video exists or not + * audioTrackSize Size of audio track in bytes + * videoTrackSize Size of video track in bytes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeMOOV(MP4HandleImp handle, mp4_u32 moovSize, mp4_bool haveAudio, mp4_bool haveVideo, trakSize *audioTrackSize, trakSize *videoTrackSize) +{ + PRINT((_L("e_writemoov 1"))); + mp4_u8 buf[8]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, moovSize); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_MOOV); + i += 4; + + PRINT((_L("e_writemoov_header 1"))); + if (writeFile(handle, buf, 8) < 0) + return -1; + PRINT((_L("e_writemoov_header 0"))); + + PRINT((_L("e_writemoov_mvhd 1"))); + if (writeMVHD(handle) < 0) + return -1; + PRINT((_L("e_writemoov_mvhd 0"))); + + PRINT((_L("e_writemoov_video 1"))); + if (haveVideo) + if (writeVideoTrak(handle, videoTrackSize) < 0) + return -1; + PRINT((_L("e_writemoov_video 0"))); + + PRINT((_L("e_writemoov_audio 1"))); + if (haveAudio) + if (writeAudioTrak(handle, audioTrackSize) < 0) + return -1; + PRINT((_L("e_writemoov_audio 0"))); + + PRINT((_L("e_writemoov_udta 1"))); + if (handle->moovUDTA) + { + if (writeUDTA(handle, handle->moovUDTA) < 0) + { + return -1; + } + } + PRINT((_L("e_writemoov_udta 0"))); + PRINT((_L("e_writemoov 0"))); + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeMVHD(MP4HandleImp handle) + * + * Description: + * + * Write MVHD atom. + * + * Parameters: + * + * handle MP4 library handle + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeMVHD(MP4HandleImp handle) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 u32; + + size_t mvhdSize = mvhdAtomSize(handle); + + buf = (mp4_u8 *)mp4malloc(mvhdSize); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)mvhdSize); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_MVHD); + i += 4; + + + if (handle->videoDuration > MP4_INT_MAX || handle->audioDuration > MP4_INT_MAX) + { + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0x01000000); //its going to be a version 1 atom + i += 4; + + /* Creation time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu64(buf+i, (mp4_u64)u32); + i += 8; + + /* Modification time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu64(buf+i, (mp4_u64)u32); + i += 8; + + /* Timescale */ + insertu32(buf+i, (mp4_u32)MVHD_TIMESCALE); + i += 4; + + /* Duration */ + { + mp4_u64 u64; + mp4_u64 videoDuration = 0; + mp4_u64 audioDuration = 0; + + + if (handle->videoTimeScale) + videoDuration = (mp4_u64)((mp4_double)MVHD_TIMESCALE * + (mp4_double)handle->videoDuration / + (mp4_double)handle->videoTimeScale + + (mp4_double)0.5); + if (handle->audioTimeScale) + audioDuration = (mp4_u64)((mp4_double)MVHD_TIMESCALE * + (mp4_double)handle->audioDuration / + (mp4_double)handle->audioTimeScale + + (mp4_double)0.5); + + if (audioDuration > videoDuration) + u64 = audioDuration; + else + u64 = videoDuration; + + insertu64(buf+i, u64); + i += 8; + } + + } + else + { + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Creation time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu32(buf+i, (mp4_u32)u32); + i += 4; + + /* Modification time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu32(buf+i, (mp4_u32)u32); + i += 4; + + /* Timescale */ + insertu32(buf+i, (mp4_u32)MVHD_TIMESCALE); + i += 4; + + /* Duration */ + { + mp4_u32 videoDuration = 0; + mp4_u32 audioDuration = 0; + + + if (handle->videoTimeScale) + videoDuration = (mp4_u32)((mp4_double)MVHD_TIMESCALE * + (mp4_double)handle->videoDuration / + (mp4_double)handle->videoTimeScale + + (mp4_double)0.5); + if (handle->audioTimeScale) + audioDuration = (mp4_u32)((mp4_double)MVHD_TIMESCALE * + (mp4_double)handle->audioDuration / + (mp4_double)handle->audioTimeScale + + (mp4_double)0.5); + + if (audioDuration > videoDuration) + u32 = audioDuration; + else + u32 = videoDuration; + + insertu32(buf+i, u32); + i += 4; + } + } + /* Reserved */ + insertu32(buf+i, (mp4_u32)0x00010000); + i += 4; + + insertu16(buf+i, (mp4_u16)0x0100); + i += 2; + + insertu16(buf+i, (mp4_u16)0x0000); + i += 2; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00010000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00010000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x40000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00010000); + i += 4; + + if (writeFile(handle, buf, mvhdSize) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoTrak(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video track atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoTrak(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[8]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->trak); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_TRAK); + i += 4; + + if (writeFile(handle, buf, 8) < 0) + return -1; + + if (writeVideoTKHD(handle, ts) < 0) + return -1; + + if (writeVideoMDIA(handle, ts) < 0) + return -1; + + if (handle->videoUDTA) + { + if (writeUDTA(handle, handle->videoUDTA) < 0) + return -1; + } + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoTKHD(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write TKHD atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoTKHD(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 u32; + mp4_double ud; + + + buf = (mp4_u8 *)mp4malloc(ts->tkhd); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->tkhd); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_TKHD); + i += 4; + + + if (handle->videoDuration > MP4_INT_MAX) + { + mp4_u64 u64; + /* Version and flags */ + buf[i++] = 1; //make this a version 1 atom + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 7; /* Track enabled, used in movie and preview */ + + /* Creation time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu64(buf+i, (mp4_u64)u32); + i += 8; + + /* Modification time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu64(buf+i, (mp4_u64)u32); + i += 8; + + /* Track ID */ + insertu32(buf+i, (mp4_u32)1); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Duration */ + if ( (handle->videoDuration == 0) || (handle->videoTimeScale == 0) ) + { + ud = 0; + } + else + { + ud = (mp4_double)MVHD_TIMESCALE * (mp4_double)handle->videoDuration / (mp4_double)handle->videoTimeScale + (mp4_double)0.5; + } + + u64 = (mp4_u64)ud; + insertu64(buf+i, u64); + i += 8; + } + else + { + /* Version and flags */ + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 7; /* Track enabled, used in movie and preview */ + + /* Creation time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu32(buf+i, (mp4_u32)u32); + i += 4; + + /* Modification time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu32(buf+i, (mp4_u32)u32); + i += 4; + + /* Track ID */ + insertu32(buf+i, (mp4_u32)1); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Duration */ + if ( (handle->videoDuration == 0) || (handle->videoTimeScale == 0) ) + { + ud = 0; + } + else + { + ud = (mp4_double)MVHD_TIMESCALE * (mp4_double)handle->videoDuration / (mp4_double)handle->videoTimeScale + (mp4_double)0.5; + } + + u32 = (mp4_u32)ud; + insertu32(buf+i, u32); + i += 4; + } + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu16(buf+i, (mp4_u16)0); /* Visual track */ + i += 2; + + insertu16(buf+i, (mp4_u16)0); + i += 2; + + insertu32(buf+i, (mp4_u32)0x00010000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00010000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x40000000); + i += 4; + + insertu16(buf+i, (mp4_u16)handle->videoWidth); /* Width */ + i += 2; + + insertu16(buf+i, (mp4_u16)0); + i += 2; + + insertu16(buf+i, (mp4_u16)handle->videoHeight); /* Height */ + i += 2; + + insertu16(buf+i, (mp4_u16)0); + i += 2; + + if (writeFile(handle, buf, ts->tkhd) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoMDIA(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video MDIA atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoMDIA(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[8]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->mdia); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_MDIA); + i += 4; + + if (writeFile(handle, buf, 8) < 0) + return -1; + + if (writeVideoMDHD(handle, ts) < 0) + return -1; + + if (writeVideoHDLR(handle, ts) < 0) + return -1; + + if (writeVideoMINF(handle, ts) < 0) + return -1; + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoMDHD(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video MDHD atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoMDHD(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 u32; + + + buf = (mp4_u8 *)mp4malloc(ts->mdhd); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->mdhd); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_MDHD); + i += 4; + + if (handle->videoDuration > MP4_INT_MAX) + { + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0x01000000); //version 1 atom + i += 4; + + /* Creation time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu64(buf+i, (mp4_u64)u32); + i += 8; + + /* Modification time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu64(buf+i, (mp4_u64)u32); + i += 8; + + /* Timescale */ + insertu32(buf+i, (mp4_u32)handle->videoTimeScale); + i += 4; + + /* Duration */ + insertu64(buf+i, handle->videoDuration); + i += 8; + } + else + { + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Creation time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu32(buf+i, (mp4_u32)u32); + i += 4; + + /* Modification time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu32(buf+i, (mp4_u32)u32); + i += 4; + + /* Timescale */ + insertu32(buf+i, (mp4_u32)handle->videoTimeScale); + i += 4; + + /* Duration */ + insertu32(buf+i, (mp4_u32)handle->videoDuration); + i += 4; + } + + /* Language */ + insertu16(buf+i, (mp4_u16)0x55c4); /* 'und' */ + i += 2; + + /* Reserved */ + insertu16(buf+i, (mp4_u16)0x0000); + i += 2; + + if (writeFile(handle, buf, ts->mdhd) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoHDLR(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video HDLR atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoHDLR(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(ts->hdlr); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->hdlr); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_HDLR); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Handler type */ + buf[i++] = 'v'; + buf[i++] = 'i'; + buf[i++] = 'd'; + buf[i++] = 'e'; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Empty string */ + buf[i++] = 0; + + if (writeFile(handle, buf, ts->hdlr) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoMINF(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video MINF atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoMINF(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[8]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->minf); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_MINF); + i += 4; + + if (writeFile(handle, buf, 8) < 0) + return -1; + + if (writeVMHD(handle, ts) < 0) + return -1; + + if (writeDINF(handle, ts) < 0) + return -1; + + if (writeVideoSTBL(handle, ts) < 0) + return -1; + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVMHD(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write VMHD atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVMHD(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(ts->vmhd); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->vmhd); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_VMHD); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0x00000001); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + if (writeFile(handle, buf, ts->vmhd) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeDINF(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write DINF atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeDINF(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[8]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->dinf); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_DINF); + i += 4; + + if (writeFile(handle, buf, 8) < 0) + return -1; + + if (writeDREF(handle, ts) < 0) + return -1; + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeDREF(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write DREF atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeDREF(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(ts->dref); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->dref); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_DREF); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)1); + i += 4; + + /* URL atom */ + + /* Size */ + insertu32(buf+i, (mp4_u32)12); + i += 4; + + /* Type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_URL); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0x00000001); + i += 4; + + if (writeFile(handle, buf, ts->dref) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoSTBL(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video STBL atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSTBL(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[8]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stbl); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STBL); + i += 4; + + if (writeFile(handle, buf, 8) < 0) + return -1; + + if (writeVideoSTSD(handle, ts) < 0) + return -1; + + if (handle->flags & MP4_FLAG_LONGCLIP) + { + if (writeVideoSTTSLongClip(handle, ts) < 0) + return -1; + } + else + { + if (writeVideoSTTS(handle, ts) < 0) + return -1; + } + + if (writeVideoSTSC(handle, ts) < 0) + return -1; + + if (handle->flags & MP4_FLAG_LONGCLIP) + { + if (writeVideoSTSZLongClip(handle, ts) < 0) + return -1; + + if (handle->videoSampleTable->stcoNeed64Bits) + { + if (writeVideoCO64LongClip(handle, ts) < 0) + return -1; + } + else + { + if (writeVideoSTCOLongClip(handle, ts) < 0) + return -1; + } + + if (writeVideoSTSSLongClip(handle, ts) < 0) + return -1; + + if(ts->sdtp && writeVideoSDTPLongClip(handle, ts) < 0) + return -1; + } + else + { + if (writeVideoSTSZ(handle, ts) < 0) + return -1; + + if (handle->videoSampleTable->stcoNeed64Bits) + { + if (writeVideoCO64(handle, ts) < 0) + return -1; + } + else + { + if (writeVideoSTCO(handle, ts) < 0) + return -1; + } + + if (writeVideoSTSS(handle, ts) < 0) + return -1; + + if(ts->sdtp && writeVideoSDTP(handle, ts) < 0) + return -1; + } + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoSTSD(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video STSD atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSTSD(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[16]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stsd); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STSD); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)1); + i += 4; + + if (writeFile(handle, buf, 16) < 0) + return -1; + + if (handle->type & MP4_TYPE_MPEG4_VIDEO) + { + if (writeMP4V(handle, ts) < 0) + return -1; + } + else if ((handle->type & MP4_TYPE_H263_PROFILE_0) || + (handle->type & MP4_TYPE_H263_PROFILE_3)) + { + if (writeS263(handle, ts) < 0) + return -1; + } + else if ( containsAvcVideo( handle->type ) ) + { + if (writeAVC1(handle, ts) < 0) + return -1; + } + else + { + } + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeMP4V(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write MP4V atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeMP4V(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(86); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->mp4v); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_MP4V); + i += 4; + + /* Reserved */ + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + + /* Data reference index */ + insertu16(buf+i, (mp4_u16)1); + i += 2; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Width */ + insertu16(buf+i, (mp4_u16)handle->videoWidth); + i += 2; + + /* Height */ + insertu16(buf+i, (mp4_u16)handle->videoHeight); + i += 2; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0x00480000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00480000); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu16(buf+i, (mp4_u16)1); + i += 2; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu16(buf+i, (mp4_u16)24); + i += 2; + + insertu16(buf+i, (mp4_u16)0xffff); + i += 2; + + if (writeFile(handle, buf, 86) < 0) + { + mp4free(buf); + + return -1; + } + + if (writeVideoESD(handle, ts) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoESD(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video ESD atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoESD(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(ts->esds); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->esds); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_ESD); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* ES_DescrTag */ + buf[i++] = 0x03; + + /* Size */ + buf[i++] = (mp4_u8)(23 + handle->videoDecSpecificInfoSize); + + /* ES_ID */ + insertu16(buf+i, (mp4_u16)0); + i += 2; + + /* Flags */ + buf[i++] = 0; + + /* DecoderConfigDescrTag */ + buf[i++] = 0x04; + + /* Size */ + buf[i++] = (mp4_u8)(15 + handle->videoDecSpecificInfoSize); + + /* ObjectTypeIndication */ + buf[i++] = 0x20; + + /* Flags */ + buf[i++] = 0x11; + + /* BufferSizeDB */ + buf[i++] = 0x00; + buf[i++] = 0x50; + buf[i++] = 0x00; + + /* MaxBitrate */ + insertu32(buf+i, (mp4_u32)handle->videoMaxBitrate); + i += 4; + + /* AvgBitrate */ + insertu32(buf+i, (mp4_u32)handle->videoAvgBitrate); + i += 4; + + /* DecSpecificInfoTag */ + buf[i++] = 0x05; + + /* Size */ + buf[i++] = (mp4_u8)handle->videoDecSpecificInfoSize; + + /* DecoderSpecificInfo */ + mp4memcpy(buf+i, handle->videoDecSpecificInfo, handle->videoDecSpecificInfoSize); + i += handle->videoDecSpecificInfoSize; + + /* SLConfigDescrTag */ + buf[i++] = 0x06; + + /* Size */ + buf[i++] = 1; + + /* */ + buf[i++] = 2; + + if (writeFile(handle, buf, ts->esds) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeS263(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write S263 atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeS263(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(86); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->s263); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_S263); + i += 4; + + /* Reserved */ + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + + /* Data reference index */ + insertu16(buf+i, (mp4_u16)1); + i += 2; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Width */ + insertu16(buf+i, (mp4_u16)handle->videoWidth); + i += 2; + + /* Height */ + insertu16(buf+i, (mp4_u16)handle->videoHeight); + i += 2; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0x00480000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00480000); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu16(buf+i, (mp4_u16)1); + i += 2; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu16(buf+i, (mp4_u16)24); + i += 2; + + insertu16(buf+i, (mp4_u16)0xffff); + i += 2; + + if (writeFile(handle, buf, 86) < 0) + { + mp4free(buf); + + return -1; + } + + if (writeD263(handle, ts) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeD263(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write D263 atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeD263(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[15]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->d263); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_D263); + i += 4; + + /* Vendor */ + buf[i++] = 'S'; + buf[i++] = '6'; + buf[i++] = '0'; + buf[i++] = ' '; + + /* Decoder version */ + buf[i++] = 0; + + /* H263_Level */ + buf[i++] = handle->videoLevel; + + /* H263_Profile */ + if (handle->type & MP4_TYPE_H263_PROFILE_0) + buf[i++] = 0; + else if (handle->type & MP4_TYPE_H263_PROFILE_3) + buf[i++] = 3; + else + return -1; + + if (writeFile(handle, buf, 15) < 0) + return -1; + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeAVC1(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write AVC1 atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAVC1(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(86); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->avc1); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_AVC1); + i += 4; + + /* Reserved */ + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + + /* Data reference index */ + insertu16(buf+i, (mp4_u16)1); + i += 2; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Width */ + insertu16(buf+i, (mp4_u16)handle->videoWidth); + i += 2; + + /* Height */ + insertu16(buf+i, (mp4_u16)handle->videoHeight); + i += 2; + + /* H-res (default is 72dpi = 0x00480000) */ + insertu32(buf+i, (mp4_u32)0x00480000); + i += 4; + + /* V-res (default is 72dpi = 0x00480000) */ + insertu32(buf+i, (mp4_u32)0x00480000); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Frame count (default is 1) */ + insertu16(buf+i, (mp4_u16)1); + i += 2; + + /* Compressor name (32 byte string) */ + // The spec *recommends* inserting "\012AVC Coding" here + // but we just have a string of nulls. + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Depth (default is 0x0018 which indicates colour images with no alpha) */ + insertu16(buf+i, (mp4_u16)24); + i += 2; + + /* Pre-defined (-1) */ + insertu16(buf+i, (mp4_u16)0xffff); + i += 2; + + if (writeFile(handle, buf, 86) < 0) + { + mp4free(buf); + + return -1; + } + + if (writeAVCC(handle, ts) < 0) + { + mp4free(buf); + + return -1; + } + + /* Note: If necessary, include writing of btrt and m4ds atoms. */ + + mp4free(buf); + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeAVCC(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write AVCC atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAVCC(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(ts->avcc); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->avcc); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_AVCC); + i += 4; + + /*mp4memcpy(buf+i, handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfig, + handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfigSize);*/ + + mp4memcpy(buf+i, handle->videoDecSpecificInfo, handle->videoDecSpecificInfoSize); + + /*i += handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfigSize;*/ + + i += handle->videoDecSpecificInfoSize; + + if (writeFile(handle, buf, ts->avcc) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoSTTS(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video STTS atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSTTS(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 j; + + + buf = (mp4_u8 *)mp4malloc(ts->stts); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stts); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STTS); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->sttsEntryCount); + i += 4; + + /* Sample count and sample delta */ + for (j = 0; j < handle->videoSampleTable->sttsEntryCount; j++) + { + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->sttsSampleCount[j]); + i += 4; + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->sttsSampleDelta[j]); + i += 4; + } + + if (writeFile(handle, buf, ts->stts) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoSTTSLongClip(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video STTS atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSTTSLongClip(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u8 *buf2; + mp4_u32 i = 0; + mp4_u32 j; + mp4_u32 left; + mp4_u32 bytestoread; + + + buf = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE); + if (buf == NULL) + return -1; + + buf2 = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE / 2); + if (buf2 == NULL) + { + mp4free(buf); + return -1; + } + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stts); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STTS); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->sttsEntryCount); + i += 4; + + if (writeFile(handle, buf, i) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + /* Sample count and delta */ + + /* Seek to the beginning of temporary files */ + + if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_STTS_SAMPLE_COUNT) < 0) + { + mp4free(buf); + mp4free(buf2); + return -1; + } + if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_STTS_SAMPLE_DELTA) < 0) + { + mp4free(buf); + mp4free(buf2); + return -1; + } + + left = handle->videoSampleTable->sttsEntryCount * 4; /* Bytes left in each file */ + + while (left) + { + if (left > METADATA_COPY_BUFFERSIZE / 2) + bytestoread = METADATA_COPY_BUFFERSIZE / 2; + else + bytestoread = left; + + if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_STTS_SAMPLE_COUNT) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + for (j = 0; j < bytestoread; j += 4) + { + insertu32(buf + 2*j, ((mp4_u32 *)buf2)[j / 4]); + } + + if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_STTS_SAMPLE_DELTA) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + for (j = 0; j < bytestoread; j += 4) + { + insertu32(buf + 2*j + 4, ((mp4_u32 *)buf2)[j / 4]); + } + + if (writeFile(handle, buf, 2 * bytestoread) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + left -= bytestoread; + } + + mp4free(buf); + mp4free(buf2); + + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoSTSC(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video STSC atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSTSC(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 j; + + + buf = (mp4_u8 *)mp4malloc(ts->stsc); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stsc); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STSC); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stscEntryCount); + i += 4; + + /* First chunk, samples per chunk and sample description index */ + for (j = 0; j < handle->videoSampleTable->stscEntryCount; j++) + { + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stscFirstChunk[j]); + i += 4; + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stscSamplesPerChunk[j]); + i += 4; + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stscSampleDescriptionIndex[j]); + i += 4; + } + + if (writeFile(handle, buf, ts->stsc) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoSTSZ(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video STSZ atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSTSZ(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 j; + + + buf = (mp4_u8 *)mp4malloc(ts->stsz); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stsz); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STSZ); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Sample size */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stszSampleSize); + i += 4; + + /* Sample count */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stszSampleCount); + i += 4; + + /* Entry sizes */ + if (handle->videoSampleTable->stszSampleSize == 0) + { + for (j = 0; j < handle->videoSampleTable->stszSampleCount; j++) + { + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stszEntrySize[j]); + i += 4; + } + } + + if (writeFile(handle, buf, ts->stsz) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoSTSZLongClip(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video STSZ atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSTSZLongClip(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u8 *buf2; + mp4_u32 i = 0; + mp4_u32 j; + mp4_u32 left; + mp4_u32 bytestoread; + + + buf = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE); + if (buf == NULL) + return -1; + + buf2 = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE); + if (buf2 == NULL) + { + mp4free(buf); + return -1; + } + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stsz); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STSZ); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Sample size */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stszSampleSize); + i += 4; + + /* Sample count */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stszSampleCount); + i += 4; + + if (writeFile(handle, buf, i) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + /* Entry sizes */ + + if (handle->videoSampleTable->stszSampleSize == 0) + { + /* Seek to the beginning of temporary file */ + + if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_STSZ_ENTRY_SIZE) < 0) + { + mp4free(buf); + mp4free(buf2); + return -1; + } + + left = handle->videoSampleTable->stszSampleCount * 4; /* Bytes left in the file */ + + while (left) + { + if (left > METADATA_COPY_BUFFERSIZE) + bytestoread = METADATA_COPY_BUFFERSIZE; + else + bytestoread = left; + + if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_STSZ_ENTRY_SIZE) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + for (j = 0; j < bytestoread; j += 4) + { + insertu32(buf + j, ((mp4_u32 *)buf2)[j / 4]); + } + + if (writeFile(handle, buf, bytestoread) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + left -= bytestoread; + } + } + + mp4free(buf); + mp4free(buf2); + + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoSTCO(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video STCO atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSTCO(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 j; + + + buf = (mp4_u8 *)mp4malloc(ts->stco); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stco); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STCO); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stcoEntryCount); + i += 4; + + /* Chunk offsets */ + for (j = 0; j < handle->videoSampleTable->stcoEntryCount; j++) + { + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stcoChunkOffset[j]); + i += 4; + } + + if (writeFile(handle, buf, ts->stco) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeVideoCO64(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video CO64 atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoCO64(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 j; + + + buf = (mp4_u8 *)mp4malloc(ts->stco); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stco); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_CO64); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stcoEntryCount); + i += 4; + + /* Chunk offsets */ + for (j = 0; j < handle->videoSampleTable->stcoEntryCount; j++) + { + insertu64(buf+i, (mp4_u64)handle->videoSampleTable->stcoChunkOffset[j]); + i += 8; + } + + if (writeFile(handle, buf, ts->stco) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeVideoSTCOLongClip(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video STCO atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSTCOLongClip(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u8 *buf2; + mp4_u32 i = 0; + mp4_u32 j; + mp4_u32 left; + mp4_u32 bytestoread; + mp4_u32 bufferSize = (METADATA_COPY_BUFFERSIZE/sizeof(mp4_u64)) * sizeof(mp4_u64); //must be a multiple of u64 + //METADATA_COPY_BUFFERSIZE is only guaranteed to be a multiple of 4 + + buf = (mp4_u8 *)mp4malloc(bufferSize); + if (buf == NULL) + return -1; + + buf2 = (mp4_u8 *)mp4malloc(bufferSize); + if (buf2 == NULL) + { + mp4free(buf); + return -1; + } + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stco); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STCO); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stcoEntryCount); + i += 4; + + if (writeFile(handle, buf, i) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + /* Chunk offsets */ + + /* Seek to the beginning of temporary file */ + + if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_STCO_CHUNK_OFFSET) < 0) + { + mp4free(buf); + mp4free(buf2); + return -1; + } + + left = handle->videoSampleTable->stcoEntryCount * 8; /* Bytes left in the file */ + + while (left) + { + if (left > bufferSize) + bytestoread = bufferSize; + else + bytestoread = left; + + if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_STCO_CHUNK_OFFSET) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + for (j = 0; j < bytestoread; j += 8) + { + ((mp4_u64 *)buf2)[j / 8] += (handle->metaDataSize + MDAT_HEADER_SIZE); /* Update chunk offsets */ + insertu32(buf + j/2, ((mp4_u64 *)buf2)[j / 8]); + } + + if (writeFile(handle, buf, bytestoread/2) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + left -= bytestoread; + } + + mp4free(buf); + mp4free(buf2); + + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeVideoCO64LongClip(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video CO64 atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoCO64LongClip(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u8 *buf2; + mp4_u32 i = 0; + mp4_u32 j; + mp4_u32 left; + mp4_u32 bytestoread; + mp4_u32 bufferSize = (METADATA_COPY_BUFFERSIZE/sizeof(mp4_u64)) * sizeof(mp4_u64); //must be a multiple of u64 + //METADATA_COPY_BUFFERSIZE is only guaranteed to be a multiple of 4 + + buf = (mp4_u8 *)mp4malloc(bufferSize); + if (buf == NULL) + return -1; + + buf2 = (mp4_u8 *)mp4malloc(bufferSize); + if (buf2 == NULL) + { + mp4free(buf); + return -1; + } + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stco); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_CO64); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stcoEntryCount); + i += 4; + + if (writeFile(handle, buf, i) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + /* Chunk offsets */ + + /* Seek to the beginning of temporary file */ + + if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_STCO_CHUNK_OFFSET) < 0) + { + mp4free(buf); + mp4free(buf2); + return -1; + } + + left = handle->videoSampleTable->stcoEntryCount * 8; /* Bytes left in the file */ + + while (left) + { + if (left > bufferSize) + bytestoread = bufferSize; + else + bytestoread = left; + + if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_STCO_CHUNK_OFFSET) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + for (j = 0; j < bytestoread; j += 8) + { + ((mp4_u64 *)buf2)[j / 8] += (handle->metaDataSize + MDAT_HEADER_SIZE); /* Update chunk offsets */ + insertu64(buf + j, ((mp4_u64 *)buf2)[j / 8]); + } + + if (writeFile(handle, buf, bytestoread) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + left -= bytestoread; + } + + mp4free(buf); + mp4free(buf2); + + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeVideoSTSS(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video STSS atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSTSS(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 j; + + + buf = (mp4_u8 *)mp4malloc(ts->stss); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stss); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STSS); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stssEntryCount); + i += 4; + + /* Sample numbers */ + for (j = 0; j < handle->videoSampleTable->stssEntryCount; j++) + { + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stssSampleNumber[j]); + i += 4; + } + + if (writeFile(handle, buf, ts->stss) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeVideoSTSSLongClip(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video STSS atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSTSSLongClip(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u8 *buf2; + mp4_u32 i = 0; + mp4_u32 j; + mp4_u32 left; + mp4_u32 bytestoread; + + + buf = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE); + if (buf == NULL) + return -1; + + buf2 = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE); + if (buf2 == NULL) + { + mp4free(buf); + return -1; + } + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stss); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STSS); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stssEntryCount); + i += 4; + + if (writeFile(handle, buf, i) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + /* Sample numbers */ + + /* Seek to the beginning of temporary file */ + + if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_STSS_SAMPLE_NUMBER) < 0) + { + mp4free(buf); + mp4free(buf2); + return -1; + } + + left = handle->videoSampleTable->stssEntryCount * 4; /* Bytes left in the file */ + + while (left) + { + if (left > METADATA_COPY_BUFFERSIZE) + bytestoread = METADATA_COPY_BUFFERSIZE; + else + bytestoread = left; + + if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_STSS_SAMPLE_NUMBER) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + for (j = 0; j < bytestoread; j += 4) + { + insertu32(buf + j, ((mp4_u32 *)buf2)[j / 4]); + } + + if (writeFile(handle, buf, bytestoread) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + left -= bytestoread; + } + + mp4free(buf); + mp4free(buf2); + + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioTrak(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio track atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioTrak(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[8]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->trak); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_TRAK); + i += 4; + + if (writeFile(handle, buf, 8) < 0) + return -1; + + if (writeAudioTKHD(handle, ts) < 0) + return -1; + + if (writeAudioMDIA(handle, ts) < 0) + return -1; + + if (handle->audioUDTA) + { + if (writeUDTA(handle, handle->audioUDTA) < 0) + return -1; + } + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioTKHD(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio TKHD atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioTKHD(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 u32; + mp4_double ud; + + + buf = (mp4_u8 *)mp4malloc(ts->tkhd); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->tkhd); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_TKHD); + i += 4; + + + if (handle->audioDuration > MP4_INT_MAX) + { + mp4_u64 u64; + /* Version and flags */ + buf[i++] = 1; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 7; /* Track enabled, used in movie and preview */ + + /* Creation time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu64(buf+i, (mp4_u64)u32); + i += 8; + + /* Modification time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu64(buf+i, (mp4_u64)u32); + i += 8; + + /* Track ID */ + insertu32(buf+i, (mp4_u32)2); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Duration */ + if ( ( handle->audioTimeScale == 0 ) || ( handle->audioDuration == 0 ) ) + { + ud = 0; + } + else + { + ud = (mp4_double)MVHD_TIMESCALE * (mp4_double)handle->audioDuration / (mp4_double)handle->audioTimeScale + (mp4_double)0.5; + } + u64 = (mp4_u64)ud; + insertu64(buf+i, u64); + i += 8; + + } + else + { + /* Version and flags */ + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 7; /* Track enabled, used in movie and preview */ + + /* Creation time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu32(buf+i, (mp4_u32)u32); + i += 4; + + /* Modification time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu32(buf+i, (mp4_u32)u32); + i += 4; + + /* Track ID */ + insertu32(buf+i, (mp4_u32)2); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Duration */ + if ( ( handle->audioTimeScale == 0 ) || ( handle->audioDuration == 0 ) ) + { + ud = 0; + } + else + { + ud = (mp4_double)MVHD_TIMESCALE * (mp4_double)handle->audioDuration / (mp4_double)handle->audioTimeScale + (mp4_double)0.5; + } + u32 = (mp4_u32)ud; + insertu32(buf+i, u32); + i += 4; + } + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu16(buf+i, (mp4_u16)0x0100); /* Audio track */ + i += 2; + + insertu16(buf+i, (mp4_u16)0); + i += 2; + + insertu32(buf+i, (mp4_u32)0x00010000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00010000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x40000000); + i += 4; + + insertu32(buf+i, (mp4_u32)0); /* Audio track */ + i += 4; + + insertu32(buf+i, (mp4_u32)0); /* Audio track */ + i += 4; + + if (writeFile(handle, buf, ts->tkhd) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioMDIA(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio MDIA atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioMDIA(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[8]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->mdia); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_MDIA); + i += 4; + + if (writeFile(handle, buf, 8) < 0) + return -1; + + if (writeAudioMDHD(handle, ts) < 0) + return -1; + + if (writeAudioHDLR(handle, ts) < 0) + return -1; + + if (writeAudioMINF(handle, ts) < 0) + return -1; + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioMDHD(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio MDHD atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioMDHD(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 u32; + + + buf = (mp4_u8 *)mp4malloc(ts->mdhd); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->mdhd); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_MDHD); + i += 4; + + if (handle->audioDuration > MP4_INT_MAX) + { + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0x1000000); //version 1 atom + i += 4; + + /* Creation time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu64(buf+i, (mp4_u64)u32); + i += 8; + + /* Modification time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu64(buf+i, (mp4_u64)u32); + i += 8; + + /* Timescale */ + insertu32(buf+i, (mp4_u32)handle->audioTimeScale); + i += 4; + + /* Duration */ + insertu64(buf+i, handle->audioDuration); + i += 8; + + } + else + { + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Creation time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu32(buf+i, (mp4_u32)u32); + i += 4; + + /* Modification time */ + if (getCurrentTime(&u32) < 0) + u32 = 0; + insertu32(buf+i, (mp4_u32)u32); + i += 4; + + /* Timescale */ + insertu32(buf+i, (mp4_u32)handle->audioTimeScale); + i += 4; + + /* Duration */ + insertu32(buf+i, (mp4_u32)handle->audioDuration); + i += 4; + } + + /* Language */ + insertu16(buf+i, (mp4_u16)0x55c4); /* 'und' */ + i += 2; + + /* Reserved */ + insertu16(buf+i, (mp4_u16)0x0000); + i += 2; + + if (writeFile(handle, buf, ts->mdhd) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioHDLR(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio HDLR atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioHDLR(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(ts->hdlr); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->hdlr); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_HDLR); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Handler type */ + buf[i++] = 's'; + buf[i++] = 'o'; + buf[i++] = 'u'; + buf[i++] = 'n'; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Empty string */ + buf[i++] = 0; + + if (writeFile(handle, buf, ts->hdlr) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioMINF(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio MINF atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioMINF(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[8]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->minf); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_MINF); + i += 4; + + if (writeFile(handle, buf, 8) < 0) + return -1; + + if (writeSMHD(handle, ts) < 0) + return -1; + + if (writeDINF(handle, ts) < 0) + return -1; + + if (writeAudioSTBL(handle, ts) < 0) + return -1; + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeSMHD(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write SMHD atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeSMHD(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(ts->smhd); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->smhd); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_SMHD); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + if (writeFile(handle, buf, ts->smhd) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioSTBL(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio STBL atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioSTBL(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[8]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stbl); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STBL); + i += 4; + + if (writeFile(handle, buf, 8) < 0) + return -1; + + if (writeAudioSTSD(handle, ts) < 0) + return -1; + + if (handle->flags & MP4_FLAG_LONGCLIP) + { + if (writeAudioSTTSLongClip(handle, ts) < 0) + return -1; + } + else + { + if (writeAudioSTTS(handle, ts) < 0) + return -1; + } + + if (writeAudioSTSC(handle, ts) < 0) + return -1; + + if (handle->flags & MP4_FLAG_LONGCLIP) + { + if (writeAudioSTSZLongClip(handle, ts) < 0) + return -1; + + if (handle->audioSampleTable->stcoNeed64Bits) + { + if (writeAudioCO64LongClip(handle, ts) < 0) + return -1; + } + else + { + if (writeAudioSTCOLongClip(handle, ts) < 0) + return -1; + } + } + else + { + if (writeAudioSTSZ(handle, ts) < 0) + return -1; + + if (handle->audioSampleTable->stcoNeed64Bits) + { + if (writeAudioCO64(handle, ts) < 0) + return -1; + } + else + { + if (writeAudioSTCO(handle, ts) < 0) + return -1; + } + } + + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioSTSD(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio STSD atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioSTSD(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[16]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stsd); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STSD); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)1); + i += 4; + + if (writeFile(handle, buf, 16) < 0) + return -1; + + if (handle->type & MP4_TYPE_MPEG4_AUDIO) + { + if (writeMP4A(handle, ts) < 0) + return -1; + } + else if (handle->type & MP4_TYPE_AMR_NB) + { + if (writeSAMR(handle, ts) < 0) + return -1; + } + else if (handle->type & MP4_TYPE_AMR_WB) + { + if (writeSAWB(handle, ts) < 0) + return -1; + } + else if ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio)) + { + if (writeSQCP(handle, ts) < 0) + return -1; + } + else if ((handle->type & MP4_TYPE_QCELP_13K) && (handle->qcelpStoredAsMPEGAudio)) + { + if (writeMP4A(handle, ts) < 0) + return -1; + } + else + { + } + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeMP4A(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write MP4A atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeMP4A(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(36); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->mp4a); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_MP4A); + i += 4; + + /* Reserved */ + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + + /* Data reference index */ + insertu16(buf+i, (mp4_u16)1); + i += 2; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu16(buf+i, (mp4_u16)2); + i += 2; + + insertu16(buf+i, (mp4_u16)16); + i += 2; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Timescale */ + insertu16(buf+i, (mp4_u16)handle->audioTimeScale); + i += 2; + + /* Reserved */ + insertu16(buf+i, (mp4_u16)0); + i += 2; + + if (writeFile(handle, buf, 36) < 0) + { + mp4free(buf); + + return -1; + } + + if (writeAudioESD(handle, ts) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioESD(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio ESD atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioESD(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 bitrate = 0; + mp4_u32 num_of_bytes = 0; + mp4_u32 size = 0; + mp4_u32 index = 0; + mp4_u32 tempnum = 0; + + mp4_u32 size1, size2; + mp4_u32 numofsizebytes1, numofsizebytes2; + + buf = (mp4_u8 *)mp4malloc(ts->esds); + if (buf == NULL) + return -1; + + /* Calculate the necessary size information */ + size1 = handle->audioDecSpecificInfoSize; + if (size1 < 128) + numofsizebytes1 = 1; + else + { + numofsizebytes1 = 1; + while ( size1 >= 128 ) + { + size1 = size1 >> 7; + numofsizebytes1++; + } + } + + size2 = 14 + numofsizebytes1 + handle->audioDecSpecificInfoSize; + if (size2 < 128) + numofsizebytes2 = 1; + else + { + numofsizebytes2 = 1; + while ( size2 >= 128 ) + { + size2 = size2 >> 7; + numofsizebytes2++; + } + } + /* End of size calculations */ + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->esds); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_ESD); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* ES_DescrTag */ + buf[i++] = 0x03; + + /* Size */ + size = 21 + numofsizebytes1 + numofsizebytes2 + handle->audioDecSpecificInfoSize; + if (size < 128) + buf[i++] = (mp4_u8)(size); + else + { + num_of_bytes = 0; + while ( size >= 128 ) + { + size = size >> 7; + num_of_bytes++; + } + size = 21 + numofsizebytes1 + numofsizebytes2 + handle->audioDecSpecificInfoSize; + for(index = num_of_bytes; index > 0; index--) + { + tempnum = size >> (7 * index); + buf[i++] = (mp4_u8)(0x80 | (mp4_u8) tempnum); + size -= (tempnum << (7 * index)); + } + buf[i++] = (mp4_u8)size; + } + + /* ES_ID */ + insertu16(buf+i, (mp4_u16)0); + i += 2; + + /* Flags */ + buf[i++] = 0; + + /* DecoderConfigDescrTag */ + buf[i++] = 0x04; + + /* Size */ + size = 14 + numofsizebytes1 + handle->audioDecSpecificInfoSize; + if (size < 128) + buf[i++] = (mp4_u8)(size); + else + { + num_of_bytes = 0; + while ( size >= 128 ) + { + size = size >> 7; + num_of_bytes++; + } + size = 14 + numofsizebytes1 + handle->audioDecSpecificInfoSize; + for(index = num_of_bytes; index > 0; index--) + { + tempnum = size >> (7 * index); + buf[i++] = (mp4_u8)(0x80 | (mp4_u8) tempnum); + size -= (tempnum << (7 * index)); + } + buf[i++] = (mp4_u8)size; + } + + /* ObjectTypeIndication */ + if (handle->type & MP4_TYPE_MPEG4_AUDIO) + buf[i++] = 0x40; + else if ((handle->type & MP4_TYPE_QCELP_13K) && (handle->qcelpStoredAsMPEGAudio)) + buf[i++] = 0xE1; + else + { + } + + /* Flags */ + buf[i++] = 0x15; + + /* BufferSizeDB */ + if (handle->type & MP4_TYPE_MPEG4_AUDIO) + { + buf[i++] = 0x00; + buf[i++] = 0x00; + buf[i++] = 0x00; + } + else if ((handle->type & MP4_TYPE_QCELP_13K) && (handle->qcelpStoredAsMPEGAudio)) + { /* 4096 for QCELP 13K */ + buf[i++] = 0x00; + buf[i++] = 0x10; + buf[i++] = 0x00; + } + else + { + } + + + if ((handle->audioDuration != 0) && (handle->audioTimeScale != 0)) + bitrate = (mp4_u32)((mp4_double)8 * + (mp4_double)handle->audioMediaDataSize / + ((mp4_double)handle->audioDuration / + (mp4_double)handle->audioTimeScale)); + else + bitrate = 0; + + /* MaxBitrate */ + insertu32(buf+i, (mp4_u32)bitrate); /*0x00010000*/ + i += 4; + + /* AvgBitrate */ + insertu32(buf+i, (mp4_u32)bitrate);/*0x00008000*/ + i += 4; + + /* DecSpecificInfoTag */ + buf[i++] = 0x05; + + /* Size */ + size = handle->audioDecSpecificInfoSize; + if (size < 128) + buf[i++] = (mp4_u8)(size); + else + { + num_of_bytes = 0; + while ( size >= 128 ) + { + size = size >> 7; + num_of_bytes++; + } + size = handle->audioDecSpecificInfoSize; + for(index = num_of_bytes; index > 0; index--) + { + tempnum = size >> (7 * index); + buf[i++] = (mp4_u8)(0x80 | (mp4_u8) tempnum); + size -= (tempnum << (7 * index)); + } + buf[i++] = (mp4_u8)size; + } + + /* DecoderSpecificInfo */ + mp4memcpy(buf+i, handle->audioDecSpecificInfo, handle->audioDecSpecificInfoSize); + i += handle->audioDecSpecificInfoSize; + + /* SLConfigDescrTag */ + buf[i++] = 0x06; + + /* Size */ + buf[i++] = 1; + + /* */ + buf[i++] = 2; + + if (writeFile(handle, buf, ts->esds) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeSAMR(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write SAMR atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeSAMR(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(36); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->samr); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_SAMR); + i += 4; + + /* Reserved */ + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + + /* Data reference index */ + insertu16(buf+i, (mp4_u16)1); + i += 2; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu16(buf+i, (mp4_u16)2); + i += 2; + + insertu16(buf+i, (mp4_u16)16); + i += 2; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Timescale */ + insertu16(buf+i, (mp4_u16)handle->audioTimeScale); + i += 2; + + /* Reserved */ + insertu16(buf+i, (mp4_u16)0); + i += 2; + + if (writeFile(handle, buf, 36) < 0) + { + mp4free(buf); + + return -1; + } + + if (writeDAMR(handle, ts) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeSAWB(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write SAWB atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeSAWB(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(36); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->sawb); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_SAWB); + i += 4; + + /* Reserved */ + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + + /* Data reference index */ + insertu16(buf+i, (mp4_u16)1); + i += 2; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu16(buf+i, (mp4_u16)2); + i += 2; + + insertu16(buf+i, (mp4_u16)16); + i += 2; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Timescale */ + insertu16(buf+i, (mp4_u16)handle->audioTimeScale); + i += 2; + + /* Reserved */ + insertu16(buf+i, (mp4_u16)0); + i += 2; + + if (writeFile(handle, buf, 36) < 0) + { + mp4free(buf); + + return -1; + } + + if (writeDAMR(handle, ts) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeDAMR(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write DAMR atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeDAMR(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[17]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->damr); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_DAMR); + i += 4; + + /* Vendor */ + buf[i++] = 'S'; + buf[i++] = '6'; + buf[i++] = '0'; + buf[i++] = ' '; + + /* Decoder version */ + buf[i++] = 0; + + /* Mode set */ + insertu16(buf+i, (mp4_u16)handle->audioModeSet); + i += 2; + + /* Mode change period */ + buf[i++] = 0; + + /* Frames per sample */ + buf[i++] = handle->audioFramesPerSample; + + if (writeFile(handle, buf, 17) < 0) + return -1; + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioSTTS(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio STTS atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioSTTS(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 j; + + + buf = (mp4_u8 *)mp4malloc(ts->stts); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stts); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STTS); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->sttsEntryCount); + i += 4; + + /* Sample count and sample delta */ + for (j = 0; j < handle->audioSampleTable->sttsEntryCount; j++) + { + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->sttsSampleCount[j]); + i += 4; + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->sttsSampleDelta[j]); + i += 4; + } + + if (writeFile(handle, buf, ts->stts) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioSTTSLongClip(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio STTS atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioSTTSLongClip(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u8 *buf2; + mp4_u32 i = 0; + mp4_u32 j; + mp4_u32 left; + mp4_u32 bytestoread; + + + buf = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE); + if (buf == NULL) + return -1; + + buf2 = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE / 2); + if (buf2 == NULL) + { + mp4free(buf); + return -1; + } + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stts); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STTS); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->sttsEntryCount); + i += 4; + + if (writeFile(handle, buf, i) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + /* Sample count and delta */ + + /* Seek to the beginning of temporary files */ + + if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_AUDIO_STTS_SAMPLE_COUNT) < 0) + { + mp4free(buf); + mp4free(buf2); + return -1; + } + if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_AUDIO_STTS_SAMPLE_DELTA) < 0) + { + mp4free(buf); + mp4free(buf2); + return -1; + } + + left = handle->audioSampleTable->sttsEntryCount * 4; /* Bytes left in each file */ + + while (left) + { + if (left > METADATA_COPY_BUFFERSIZE / 2) + bytestoread = METADATA_COPY_BUFFERSIZE / 2; + else + bytestoread = left; + + if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_AUDIO_STTS_SAMPLE_COUNT) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + for (j = 0; j < bytestoread; j += 4) + { + insertu32(buf + 2*j, ((mp4_u32 *)buf2)[j / 4]); + } + + if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_AUDIO_STTS_SAMPLE_DELTA) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + for (j = 0; j < bytestoread; j += 4) + { + insertu32(buf + 2*j + 4, ((mp4_u32 *)buf2)[j / 4]); + } + + if (writeFile(handle, buf, 2 * bytestoread) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + left -= bytestoread; + } + + mp4free(buf); + mp4free(buf2); + + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioSTSC(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio STSC atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioSTSC(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 j; + + + buf = (mp4_u8 *)mp4malloc(ts->stsc); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stsc); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STSC); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stscEntryCount); + i += 4; + + /* First chunk, samples per chunk and sample description index */ + for (j = 0; j < handle->audioSampleTable->stscEntryCount; j++) + { + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stscFirstChunk[j]); + i += 4; + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stscSamplesPerChunk[j]); + i += 4; + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stscSampleDescriptionIndex[j]); + i += 4; + } + + if (writeFile(handle, buf, ts->stsc) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioSTSZ(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio STSZ atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioSTSZ(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 j; + + + buf = (mp4_u8 *)mp4malloc(ts->stsz); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stsz); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STSZ); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Sample size */ + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stszSampleSize); + i += 4; + + /* Sample count */ + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stszSampleCount); + i += 4; + + /* Entry sizes */ + if (handle->audioSampleTable->stszSampleSize == 0) + { + for (j = 0; j < handle->audioSampleTable->stszSampleCount; j++) + { + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stszEntrySize[j]); + i += 4; + } + } + + if (writeFile(handle, buf, ts->stsz) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioSTSZLongClip(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio STSZ atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioSTSZLongClip(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u8 *buf2; + mp4_u32 i = 0; + mp4_u32 j; + mp4_u32 left; + mp4_u32 bytestoread; + + + buf = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE); + if (buf == NULL) + return -1; + + buf2 = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE); + if (buf2 == NULL) + { + mp4free(buf); + return -1; + } + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stsz); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STSZ); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Sample size */ + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stszSampleSize); + i += 4; + + /* Sample count */ + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stszSampleCount); + i += 4; + + if (writeFile(handle, buf, i) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + /* Entry sizes */ + + if (handle->audioSampleTable->stszSampleSize == 0) + { + /* Seek to the beginning of temporary file */ + + if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_AUDIO_STSZ_ENTRY_SIZE) < 0) + { + mp4free(buf); + mp4free(buf2); + return -1; + } + + left = handle->audioSampleTable->stszSampleCount * 4; /* Bytes left in the file */ + + while (left) + { + if (left > METADATA_COPY_BUFFERSIZE) + bytestoread = METADATA_COPY_BUFFERSIZE; + else + bytestoread = left; + + if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_AUDIO_STSZ_ENTRY_SIZE) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + for (j = 0; j < bytestoread; j += 4) + { + insertu32(buf + j, ((mp4_u32 *)buf2)[j / 4]); + } + + if (writeFile(handle, buf, bytestoread) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + left -= bytestoread; + } + } + + mp4free(buf); + mp4free(buf2); + + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeAudioSTCO(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio STCO atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioSTCO(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 j; + + + buf = (mp4_u8 *)mp4malloc(ts->stco); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stco); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STCO); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stcoEntryCount); + i += 4; + + /* Chunk offsets */ + for (j = 0; j < handle->audioSampleTable->stcoEntryCount; j++) + { + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stcoChunkOffset[j]); + i += 4; + } + + if (writeFile(handle, buf, ts->stco) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeAudioCO64(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio CO64 atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioCO64(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 j; + + + buf = (mp4_u8 *)mp4malloc(ts->stco); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stco); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_CO64); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stcoEntryCount); + i += 4; + + /* Chunk offsets */ + for (j = 0; j < handle->audioSampleTable->stcoEntryCount; j++) + { + insertu64(buf+j, (mp4_u64)handle->audioSampleTable->stcoChunkOffset[j]); + } + + if (writeFile(handle, buf, ts->stco) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeAudioSTCOLongClip(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio STCO atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioSTCOLongClip(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u8 *buf2; + mp4_u32 i = 0; + mp4_u32 j; + mp4_u32 left; + mp4_u32 bytestoread; + mp4_u32 bufferSize = (METADATA_COPY_BUFFERSIZE/sizeof(mp4_u64)) * sizeof(mp4_u64); //must be a multiple of u64 + //METADATA_COPY_BUFFERSIZE is only guaranteed to be a multiple of 4 + + + buf = (mp4_u8 *)mp4malloc(bufferSize); + if (buf == NULL) + return -1; + + buf2 = (mp4_u8 *)mp4malloc(bufferSize); + if (buf2 == NULL) + { + mp4free(buf); + return -1; + } + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stco); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_STCO); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stcoEntryCount); + i += 4; + + if (writeFile(handle, buf, i) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + /* Chunk offsets */ + + /* Seek to the beginning of temporary file */ + + if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_AUDIO_STCO_CHUNK_OFFSET) < 0) + { + mp4free(buf); + mp4free(buf2); + return -1; + } + + left = handle->audioSampleTable->stcoEntryCount * 8; /* Bytes left in the file */ + + while (left) + { + if (left > bufferSize) + bytestoread = bufferSize; + else + bytestoread = left; + + if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_AUDIO_STCO_CHUNK_OFFSET) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + for (j = 0; j < bytestoread; j += 8) + { + ((mp4_u64 *)buf2)[j / 8] += (handle->metaDataSize + MDAT_HEADER_SIZE); /* Update chunk offsets */ + insertu32(buf + j/2, ((mp4_u64 *)buf2)[j / 8]); + } + + if (writeFile(handle, buf, bytestoread/2) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + left -= bytestoread; + } + + mp4free(buf); + mp4free(buf2); + + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeAudioCO64LongClip(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write audio CO64 atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAudioCO64LongClip(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u8 *buf2; + mp4_u32 i = 0; + mp4_u32 j; + mp4_u32 left; + mp4_u32 bytestoread; + mp4_u32 bufferSize = (METADATA_COPY_BUFFERSIZE/sizeof(mp4_u64)) * sizeof(mp4_u64); //must be a multiple of u64 + //METADATA_COPY_BUFFERSIZE is only guaranteed to be a multiple of 4 + + + buf = (mp4_u8 *)mp4malloc(bufferSize); + if (buf == NULL) + return -1; + + buf2 = (mp4_u8 *)mp4malloc(bufferSize); + if (buf2 == NULL) + { + mp4free(buf); + return -1; + } + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->stco); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_CO64); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Entry count */ + insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stcoEntryCount); + i += 4; + + if (writeFile(handle, buf, i) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + /* Chunk offsets */ + + /* Seek to the beginning of temporary file */ + + if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_AUDIO_STCO_CHUNK_OFFSET) < 0) + { + mp4free(buf); + mp4free(buf2); + return -1; + } + + left = handle->audioSampleTable->stcoEntryCount * 8; /* Bytes left in the file */ + + while (left) + { + if (left > bufferSize) + bytestoread = bufferSize; + else + bytestoread = left; + + if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_AUDIO_STCO_CHUNK_OFFSET) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + for (j = 0; j < bytestoread; j += 8) + { + ((mp4_u64 *)buf2)[j / 8] += (handle->metaDataSize + MDAT_HEADER_SIZE); /* Update chunk offsets */ + insertu64(buf + j, ((mp4_u64 *)buf2)[j / 8]); + } + + if (writeFile(handle, buf, bytestoread) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + left -= bytestoread; + } + + mp4free(buf); + mp4free(buf2); + + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeMediaData(MP4HandleImp handle) + * + * Description: + * + * This function writes media data to the output file. + * + * Before writing media data to the output file, meta data has + * been written to the file. Media data that is in tmpfile is + * read from there and written to the end of the output file. + * + * Parameters: + * + * handle MP4 library handle + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeMediaData(MP4HandleImp handle) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u64 left; + mp4_u32 bytestoread; + + + buf = (mp4_u8 *)mp4malloc(1024); + if (buf == NULL) + return -1; + + + i = formatMdatHeader(buf, handle->bytesInTmpFile); + if (writeFile(handle, buf, i) < 0) + { + mp4free(buf); + + return -1; + } + + /* Seek to the beginning of tmpfile */ + if (seekTmpFileAbs(handle, 0) < 0) + { + mp4free(buf); + return -1; + } + + left = handle->bytesInTmpFile; + + while (left) + { + if (left > 1024) + bytestoread = 1024; + else + bytestoread = left; + + if (readTmpFile(handle, buf, bytestoread) < 0) + { + mp4free(buf); + + return -1; + } + + if (writeFile(handle, buf, bytestoread) < 0) + { + mp4free(buf); + + return -1; + } + + left -= bytestoread; + } + + mp4free(buf); + + return 0; +} + +/* + * Function: + * + * mp4_i32 insertu64(mp4_u8 *buf, + * mp4_u64 value) + * + * Description: + * + * This function writes value into buf taking into account the endianism + * of the current computer. + * + * It is assumed that the caller of the function has allocated enough + * space for buf. + * + * Parameters: + * + * buf Buffer to write to + * value Value to write to buf + * + * Return value: + * + * 0 Success + * + */ +mp4_i32 insertu64(mp4_u8 *buf, mp4_u64 value) +{ + mp4_u64 u64; + + + u64 = u64endian(value); + mp4memcpy(buf, &u64, sizeof(mp4_u64)); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 insertu32(mp4_u8 *buf, + * mp4_u32 value) + * + * Description: + * + * This function writes value into buf taking into account the endianism + * of the current computer. + * + * It is assumed that the caller of the function has allocated enough + * space for buf. + * + * Parameters: + * + * buf Buffer to write to + * value Value to write to buf + * + * Return value: + * + * 0 Success + * + */ +mp4_i32 insertu32(mp4_u8 *buf, mp4_u32 value) +{ + mp4_u32 u32; + + + u32 = u32endian(value); + mp4memcpy(buf, &u32, 4); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 insertu16(mp4_u8 *buf, + * mp4_u16 value) + * + * Description: + * + * This function writes value into buf taking into account the endianism + * of the current computer. + * + * It is assumed that the caller of the function has allocated enough + * space for buf. + * + * Parameters: + * + * buf Buffer to write to + * value Value to write to buf + * + * Return value: + * + * 0 Success + * + */ +mp4_i32 insertu16(mp4_u8 *buf, mp4_u16 value) +{ + mp4_u16 u16; + + + u16 = u16endian(value); + mp4memcpy(buf, &u16, 2); + + return 0; +} + + +/* + * Function: + * + * mp4_i32 writeMetaDataTmp(MP4HandleImp handle) + * + * Description: + * + * This function writes metadata accumulated in memory to the disk. + * + * Parameters: + * + * handle MP4 library handle + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeMetaDataTmp(MP4HandleImp handle) +{ + PRINT((_L("e_writemetadatatmp 1"))); + if (handle->videoSampleTable) + { + PRINT((_L("e_writemetadatatmp_writemetadata_video 1"))); + if (writeMetaDataFileNum(handle, + (mp4_u8 *)handle->videoSampleTable->sttsSampleCount, + handle->videoSampleTable->sttsCurrentEntryCount * sizeof(mp4_u32), + METADATAFILE_VIDEO_STTS_SAMPLE_COUNT) < 0) + return -1; + + if (writeMetaDataFileNum(handle, + (mp4_u8 *)handle->videoSampleTable->sttsSampleDelta, + handle->videoSampleTable->sttsCurrentEntryCount * sizeof(mp4_u32), + METADATAFILE_VIDEO_STTS_SAMPLE_DELTA) < 0) + return -1; + + if (writeMetaDataFileNum(handle, + (mp4_u8 *)handle->videoSampleTable->stszEntrySize, + handle->videoSampleTable->stszCurrentSampleCount * sizeof(mp4_u32), + METADATAFILE_VIDEO_STSZ_ENTRY_SIZE) < 0) + return -1; + + if (writeMetaDataFileNum(handle, + (mp4_u8 *)handle->videoSampleTable->stcoChunkOffset, + handle->videoSampleTable->stcoCurrentEntryCount * sizeof(mp4_u64), + METADATAFILE_VIDEO_STCO_CHUNK_OFFSET) < 0) + return -1; + + if (writeMetaDataFileNum(handle, + (mp4_u8 *)handle->videoSampleTable->stssSampleNumber, + handle->videoSampleTable->stssCurrentEntryCount * sizeof(mp4_u32), + METADATAFILE_VIDEO_STSS_SAMPLE_NUMBER) < 0) + return -1; + + if (writeMetaDataFileNum(handle, + (mp4_u8 *)handle->videoSampleTable->sdtpSampleDependency, + handle->videoSampleTable->sdtpCurrentEntryCount * sizeof(mp4_u8), + METADATAFILE_VIDEO_SDTP_SAMPLE_DEPENDENCY) < 0) + return -1; + PRINT((_L("e_writemetadatatmp_writemetadata_video 0"))); + } + + if (handle->audioSampleTable) + { + PRINT((_L("e_writemetadatatmp_writemetadata_audio 1"))); + if (writeMetaDataFileNum(handle, + (mp4_u8 *)handle->audioSampleTable->sttsSampleCount, + handle->audioSampleTable->sttsCurrentEntryCount * sizeof(mp4_u32), + METADATAFILE_AUDIO_STTS_SAMPLE_COUNT) < 0) + return -1; + + if (writeMetaDataFileNum(handle, + (mp4_u8 *)handle->audioSampleTable->sttsSampleDelta, + handle->audioSampleTable->sttsCurrentEntryCount * sizeof(mp4_u32), + METADATAFILE_AUDIO_STTS_SAMPLE_DELTA) < 0) + return -1; + + if (writeMetaDataFileNum(handle, + (mp4_u8 *)handle->audioSampleTable->stszEntrySize, + handle->audioSampleTable->stszCurrentSampleCount * sizeof(mp4_u32), + METADATAFILE_AUDIO_STSZ_ENTRY_SIZE) < 0) + return -1; + + if (writeMetaDataFileNum(handle, + (mp4_u8 *)handle->audioSampleTable->stcoChunkOffset, + handle->audioSampleTable->stcoCurrentEntryCount * sizeof(mp4_u64), + METADATAFILE_AUDIO_STCO_CHUNK_OFFSET) < 0) + return -1; + PRINT((_L("e_writemetadatatmp_writemetadata_audio 0"))); + } + + if (handle->videoSampleTable) + { + handle->videoSampleTable->sttsCurrentEntryCount = 0; + handle->videoSampleTable->stszCurrentSampleCount = 0; + handle->videoSampleTable->stcoCurrentEntryCount = 0; + handle->videoSampleTable->stssCurrentEntryCount = 0; + handle->videoSampleTable->sdtpCurrentEntryCount = 0; + } + + if (handle->audioSampleTable) + { + handle->audioSampleTable->sttsCurrentEntryCount = 0; + handle->audioSampleTable->stszCurrentSampleCount = 0; + handle->audioSampleTable->stcoCurrentEntryCount = 0; + } + + handle->metaDataBlocks = 0; + handle->metaDataOnDisk = MP4TRUE; + + PRINT((_L("e_writemetadatatmp 0"))); + return 0; +} + +/* + * Function: + * + * mp4_i32 writeSQCP(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write SQCP atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeSQCP(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(36); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->sqcp); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_SQCP); + i += 4; + + /* Reserved */ + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + + /* Data reference index */ + insertu16(buf+i, (mp4_u16)1); + i += 2; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu16(buf+i, (mp4_u16)2); + i += 2; + + insertu16(buf+i, (mp4_u16)16); + i += 2; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Timescale */ + insertu16(buf+i, (mp4_u16)handle->audioTimeScale); + i += 2; + + /* Reserved */ + insertu16(buf+i, (mp4_u16)0); + i += 2; + + if (writeFile(handle, buf, 36) < 0) + { + mp4free(buf); + + return -1; + } + + if (writeDQCP(handle, ts) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeDQCP(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write DQCP atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeDQCP(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 buf[14]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->dqcp); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_DQCP); + i += 4; + + /* Vendor */ + buf[i++] = 'n'; + buf[i++] = 'o'; + buf[i++] = 'k'; + buf[i++] = 'i'; + + /* Decoder version */ + buf[i++] = 0; + + /* Mode set */ +// insertu16(buf+i, (mp4_u16)handle->audioModeSet); +// i += 2; + + /* Mode change period */ +// buf[i++] = 0; + + /* Frames per sample */ + buf[i++] = handle->audioFramesPerSample; + + if (writeFile(handle, buf, 14) < 0) + return -1; + + return 0; +} + +/* + * Function: + * + * mp4_i32 calculateES_DescriptorSize(mp4_u32 type) + * + * Description: + * + * Calculated the ES_Descriptor size inside the ESDS box. + * Updates handle->ES_DescriptorSize; + * + * Parameters: + * + * handle MP4 library handle + * type the media type: + * MP4_TYPE_QCELP_13K + * MP4_TYPE_MPEG_AUDIO + * MP4_TYPE_MPEG4_VIDEO + * + * Return value: + * + * 0 Success + * + */ +mp4_i32 calculateES_DescriptorSize(MP4HandleImp handle, mp4_u32 type) +{ + mp4_u32 size1, size2, size3; + mp4_u32 numofsizebytes1, numofsizebytes2, numofsizebytes3; + mp4_u32 decspecinfosize = 0; + + if (((type & MP4_TYPE_QCELP_13K) && (handle->qcelpStoredAsMPEGAudio)) || + (type & MP4_TYPE_MPEG4_AUDIO)) + decspecinfosize = handle->audioDecSpecificInfoSize; + else /* MPEG video case */ + decspecinfosize = handle->videoDecSpecificInfoSize; + + size1 = decspecinfosize; + if (size1 < 128) + numofsizebytes1 = 1; + else + { + numofsizebytes1 = 1; + while ( size1 >= 128 ) + { + size1 = size1 >> 7; + numofsizebytes1++; + } + } + + size2 = 14 + numofsizebytes1 + decspecinfosize; + if (size2 < 128) + numofsizebytes2 = 1; + else + { + numofsizebytes2 = 1; + while ( size2 >= 128 ) + { + size2 = size2 >> 7; + numofsizebytes2++; + } + } + + size3 = 21 + numofsizebytes1 + numofsizebytes2 + decspecinfosize; + if (size3 < 128) + numofsizebytes3 = 1; + else + { + numofsizebytes3 = 1; + while ( size3 >= 128 ) + { + size3 = size3 >> 7; + numofsizebytes3++; + } + } + + /* ES_DescriptorSize contains the size of the ES_Descriptor Field, including the 0x03 (ES_ID Tag) */ + handle->ES_DescriptorSize = 21 + numofsizebytes1 + numofsizebytes2 + decspecinfosize + numofsizebytes3 + 1; + return 0; +} + +/* + * Function: + * + * mp4_i32 writeUDTA(MP4HandleImp handle, + * userDataAtom *udta) + * + * Description: + * + * Write UDTA atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeUDTA(MP4HandleImp handle, userDataAtom *udta) +{ + mp4_u8 buf[8]; + mp4_u32 i = 0; + + + /* Size */ + insertu32(buf+i, 8 + (mp4_u32)udta->atomcontentsize); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_UDTA); + i += 4; + + if (writeFile(handle, buf, 8) < 0) + return -1; + + if (writeFile(handle, udta->contentdata, udta->atomcontentsize) < 0) + return -1; + + return 0; +} + +/* + * Function: + * + * mp4_i32 updateVideoDependencyMetaData(MP4HandleImp handle, + * mp4_u8 aDependsOn, + * mp4_u8 aIsDependentOn, + * mp4_u8 aHasRedundancy) + * + * Description: + * + * Updates SDTP video dependency data + * + * Parameters: + * + * handle MP4 library handle + * aDependsOn This frame's dependency on other frames + * aIsDependentOn Other frames's dependency on this frame + * aHasRedundancy Whether there is redundant coding in this frame + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 updateVideoDependencyMetaData(MP4HandleImp handle, mp4_u8 aDependsOn, mp4_u8 aIsDependentOn, mp4_u8 aHasRedundancy) +{ + if (handle->flags & MP4_FLAG_LONGCLIP) + { + if (handle->videoSampleTable->sdtpCurrentEntryCount == handle->videoSampleTable->sdtpMaxEntryCount) + { + void *p; + + p = mp4realloc(handle->videoSampleTable->sdtpSampleDependency, + 2 * sizeof(mp4_u8) * handle->videoSampleTable->sdtpMaxEntryCount, + sizeof(mp4_u8) * handle->videoSampleTable->stssMaxEntryCount); + if (p == NULL) + return -1; + + handle->videoSampleTable->sdtpSampleDependency = (mp4_u8 *)p; + + handle->videoSampleTable->sdtpMaxEntryCount *= 2; + } + + handle->videoSampleTable->sdtpSampleDependency[handle->videoSampleTable->sdtpCurrentEntryCount] = (aDependsOn << 4) | (aIsDependentOn << 2) | (aHasRedundancy); + handle->videoSampleTable->sdtpCurrentEntryCount++; + handle->videoSampleTable->sdtpEntryCount++; + } + else + { + if (handle->videoSampleTable->sdtpEntryCount == handle->videoSampleTable->sdtpMaxEntryCount) + { + void *p; + + p = mp4realloc(handle->videoSampleTable->sdtpSampleDependency, + 2 * sizeof(mp4_u8) * handle->videoSampleTable->sdtpMaxEntryCount, + sizeof(mp4_u8) * handle->videoSampleTable->sdtpMaxEntryCount); + if (p == NULL) + return -1; + + handle->videoSampleTable->sdtpSampleDependency = (mp4_u8 *)p; + + handle->videoSampleTable->sdtpMaxEntryCount *= 2; + } + + handle->videoSampleTable->sdtpSampleDependency[handle->videoSampleTable->sdtpEntryCount] = (aDependsOn << 4) | (aIsDependentOn << 2) | (aHasRedundancy); + handle->videoSampleTable->sdtpEntryCount++; + } + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeVideoSDTP(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video SDTP atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSDTP(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + mp4_u32 j; + + buf = (mp4_u8 *)mp4malloc(ts->sdtp); + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->sdtp); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_SDTP); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Sample dependencies */ + for (j = 0; j < handle->videoSampleTable->sdtpEntryCount; j++) + { + buf[i++] = (mp4_u8)handle->videoSampleTable->sdtpSampleDependency[j]; + } + + if (writeFile(handle, buf, ts->sdtp) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeVideoSDTPLongClip(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write video SDTP atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeVideoSDTPLongClip(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u8 *buf2; + mp4_u32 i = 0; + mp4_u32 left; + mp4_u32 bytestoread; + + + buf = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE); + if (buf == NULL) + return -1; + + buf2 = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE / 2); + if (buf2 == NULL) + { + mp4free(buf); + return -1; + } + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->sdtp); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_SDTP); + i += 4; + + /* Version and flags */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + if (writeFile(handle, buf, i) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + /* Sample count and delta */ + + /* Seek to the beginning of temporary files */ + + if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_SDTP_SAMPLE_DEPENDENCY) < 0) + { + mp4free(buf); + mp4free(buf2); + return -1; + } + + left = handle->videoSampleTable->sdtpEntryCount; /* Bytes left in each file */ + + while (left) + { + if (left > METADATA_COPY_BUFFERSIZE / 2) + bytestoread = METADATA_COPY_BUFFERSIZE / 2; + else + bytestoread = left; + + if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_SDTP_SAMPLE_DEPENDENCY) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + if (writeFile(handle, buf2, bytestoread) < 0) + { + mp4free(buf); + mp4free(buf2); + + return -1; + } + + left -= bytestoread; + } + + mp4free(buf); + mp4free(buf2); + + + return 0; +} + +/* + * Function: + * + * mp4_i32 writeAVCP(MP4HandleImp handle, + * trakSize *ts) + * + * Description: + * + * Write AVCP atom. + * + * Parameters: + * + * handle MP4 library handle + * ts Atom sizes + * + * Return value: + * + * 0 Success + * -1 Error + * + */ +mp4_i32 writeAVCP(MP4HandleImp handle, trakSize *ts) +{ + mp4_u8 *buf; + mp4_u32 i = 0; + + + buf = (mp4_u8 *)mp4malloc(86+7); // 86 = size of VisualSampleEntry, 7 = size of AVCDecoderConfigurationRecord + // with PPS and SPS sizes set to 0 + if (buf == NULL) + return -1; + + /* Size */ + insertu32(buf+i, (mp4_u32)ts->avcp); + i += 4; + + /* Atom type */ + insertu32(buf+i, (mp4_u32)ATOMTYPE_AVCP); + i += 4; + + /* Reserved */ + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + + /* Data reference index */ + insertu16(buf+i, (mp4_u16)1); + i += 2; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + /* Width */ + insertu16(buf+i, (mp4_u16)handle->videoWidth); + i += 2; + + /* Height */ + insertu16(buf+i, (mp4_u16)handle->videoHeight); + i += 2; + + /* Reserved */ + insertu32(buf+i, (mp4_u32)0x00480000); + i += 4; + + insertu32(buf+i, (mp4_u32)0x00480000); + i += 4; + + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu16(buf+i, (mp4_u16)1); + i += 2; + +// Compressorname + buf[i++] = 14; + insertu32(buf+i, (mp4_u32)0x41564320); // "AVC " + i += 4; + insertu32(buf+i, (mp4_u32)0x70617261); // "para" + i += 4; + insertu32(buf+i, (mp4_u32)0x6d657465); // "mete" + i += 4; + insertu16(buf+i, (mp4_u16)0x7273); // "rs" + i += 2; + buf[i++] = 0; + insertu32(buf+i, (mp4_u32)0); + i += 4; + insertu32(buf+i, (mp4_u32)0); + i += 4; + insertu32(buf+i, (mp4_u32)0); + i += 4; + insertu32(buf+i, (mp4_u32)0); + i += 4; + + insertu16(buf+i, (mp4_u16)24); + i += 2; + + insertu16(buf+i, (mp4_u16)0xffff); + i += 2; + + // AVCC without picparams & seqparams + mp4memcpy(buf+i, handle->videoDecSpecificInfo, 5); // 5 = configurationVersion + AVCProfileIndication + + // profile_compatibility + AVCLevelIndication + + // '111111' + lengthSizeMinusOne (2 bits) + i += 5; + buf[i++] = 0xE0 | 0; // '111' + numOfSequenceParameterSets (5 bits) + buf[i++] = 0; // numOfPictureParameterSets + + if (writeFile(handle, buf, 86+7) < 0) + { + mp4free(buf); + + return -1; + } + + mp4free(buf); + + return 0; +} + +/* + * Function: + * + * mp4_i32 formatMdatHeader(mp4_u8 *buffer, + * mp4_u64 size) + * + * Description: + * + * Formats the MDAT header into buffer + * + * Parameters: + * + * buffer buffer to write the MDAT header into + * size Size of the media data (excluding the MDAT header) + * + * Return value: + * + * size of header + * + */ +mp4_i32 formatMdatHeader(mp4_u8 *buf, mp4_u64 size) +{ + TInt i = 0; + if (size < MP4_INT_MAX) + { + //insert free box + insertu32(buf, (mp4_u32)8); + i += sizeof(mp4_u32); + insertu32(buf + i, (mp4_u32)ATOMTYPE_FREE); + i += sizeof(mp4_u32); + + //insert mdat box + insertu32(buf + i, (mp4_u32)size + 8); + i += sizeof(mp4_u32); + insertu32(buf + i, (mp4_u32)ATOMTYPE_MDAT); + i += sizeof(mp4_u32); + } + else + { + //insert mdat box + insertu32(buf + i, (mp4_u32)1); + i += sizeof(mp4_u32); + insertu32(buf + i, (mp4_u32)ATOMTYPE_MDAT); + i += sizeof(mp4_u32); + insertu64(buf + i, (mp4_u64)size + 16); + i += sizeof(mp4_u64); + } + + ASSERT(MDAT_HEADER_SIZE == i); + return i; +} + +// End of File