sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include <3gplibrary/mp4config.h> sl@0: #include <3gplibrary/mp4lib.h> sl@0: #include "mp4atom.h" sl@0: #include "mp4memwrap.h" sl@0: #include "mp4file.h" sl@0: #include "mp4buffer.h" sl@0: #include "mp4endian.h" sl@0: #include "mp4utils.h" sl@0: sl@0: using namespace ContentAccess; sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseOpen(MP4Handle *apihandle, sl@0: MP4FileName filename) sl@0: { sl@0: MP4HandleImp *handle = (MP4HandleStruct **)apihandle; sl@0: *handle = (MP4HandleImp)mp4malloc(sizeof(MP4HandleStruct)); sl@0: if (*handle == NULL) sl@0: return MP4_OUT_OF_MEMORY; sl@0: sl@0: (*handle)->file32Duplicate = NULL; sl@0: (*handle)->FileHandleFromOutside = EFalse; sl@0: (*handle)->sourceType = MP4_SOURCE_RFILE; sl@0: sl@0: if (filename) sl@0: if (initFileRead(filename, *handle) == -1) sl@0: { sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: return MP4_FILE_ERROR; sl@0: } sl@0: sl@0: (*handle)->mem = listCreate(); sl@0: if ((*handle)->mem == NULL) sl@0: { sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: return MP4_OUT_OF_MEMORY; sl@0: } sl@0: sl@0: if (((*handle)->buf = (mp4_u8 *)mp4malloc(TMPBUFSIZE)) == NULL) sl@0: { sl@0: listDestroyList((*handle)->mem); sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: return MP4_OUT_OF_MEMORY; sl@0: } sl@0: sl@0: if (((*handle)->diskReadBuf = (mp4_u8 *)mp4malloc(READBUFSIZE)) == NULL) sl@0: { sl@0: mp4free((*handle)->buf); sl@0: listDestroyList((*handle)->mem); sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: return MP4_OUT_OF_MEMORY; sl@0: } sl@0: sl@0: // register for stblib use sl@0: if (openStdlib() != MP4_OK) sl@0: { sl@0: mp4free((*handle)->diskReadBuf); sl@0: mp4free((*handle)->buf); sl@0: listDestroyList((*handle)->mem); sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseOpenFileHandle(MP4Handle *apihandle, sl@0: RFile *inputfile) sl@0: { sl@0: MP4Err err; sl@0: RFile64 *f64 = new RFile64; sl@0: if (f64 == NULL) sl@0: { sl@0: return MP4_OUT_OF_MEMORY; sl@0: } sl@0: if (f64->Duplicate(*inputfile) != KErrNone) sl@0: { sl@0: delete f64; sl@0: return MP4_ERROR; sl@0: } sl@0: err = MP4ParseOpenFileHandle64(apihandle, f64); sl@0: if (err == MP4_OK) sl@0: { sl@0: MP4HandleImp* handle = (MP4HandleStruct **)apihandle; sl@0: (*handle)->file32Duplicate = (void*)(f64); sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseOpenFileHandle64(MP4Handle *apihandle, sl@0: RFile64 *inputfile) sl@0: { sl@0: MP4HandleImp *handle = (MP4HandleStruct **)apihandle; sl@0: *handle = (MP4HandleImp)mp4malloc(sizeof(MP4HandleStruct)); sl@0: if (*handle == NULL) sl@0: return MP4_OUT_OF_MEMORY; sl@0: sl@0: (*handle)->file32Duplicate = NULL; sl@0: (*handle)->rfile = (void *)inputfile; sl@0: (*handle)->file = (*handle)->rfile; sl@0: (*handle)->FileHandleFromOutside = ETrue; sl@0: (*handle)->sourceType = MP4_SOURCE_RFILE; sl@0: if (inputfile == NULL) sl@0: { sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: return MP4_FILE_ERROR; sl@0: } sl@0: sl@0: (*handle)->mem = listCreate(); sl@0: if ((*handle)->mem == NULL) sl@0: { sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: return MP4_OUT_OF_MEMORY; sl@0: } sl@0: sl@0: if (((*handle)->buf = (mp4_u8 *)mp4malloc(TMPBUFSIZE)) == NULL) sl@0: { sl@0: listDestroyList((*handle)->mem); sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: return MP4_OUT_OF_MEMORY; sl@0: } sl@0: sl@0: if (((*handle)->diskReadBuf = (mp4_u8 *)mp4malloc(READBUFSIZE)) == NULL) sl@0: { sl@0: mp4free((*handle)->buf); sl@0: listDestroyList((*handle)->mem); sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: return MP4_OUT_OF_MEMORY; sl@0: } sl@0: sl@0: // register for stblib use sl@0: if (openStdlib() != MP4_OK) sl@0: { sl@0: // clean up sl@0: mp4free((*handle)->diskReadBuf); sl@0: mp4free((*handle)->buf); sl@0: listDestroyList((*handle)->mem); sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseOpenCAF(MP4Handle *apihandle, sl@0: ContentAccess::CData *inputfile) sl@0: { sl@0: MP4HandleImp *handle = (MP4HandleStruct **)apihandle; sl@0: *handle = (MP4HandleImp)mp4malloc(sizeof(MP4HandleStruct)); sl@0: if (*handle == NULL) sl@0: return MP4_OUT_OF_MEMORY; sl@0: sl@0: (*handle)->file32Duplicate = NULL; sl@0: (*handle)->cfile = inputfile; sl@0: (*handle)->file = (*handle)->cfile; sl@0: (*handle)->FileHandleFromOutside = ETrue; sl@0: (*handle)->sourceType = MP4_SOURCE_CAF; sl@0: sl@0: if (inputfile == NULL) sl@0: { sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: return MP4_FILE_ERROR; sl@0: } sl@0: sl@0: (*handle)->mem = listCreate(); sl@0: if ((*handle)->mem == NULL) sl@0: { sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: return MP4_OUT_OF_MEMORY; sl@0: } sl@0: sl@0: if (((*handle)->buf = (mp4_u8 *)mp4malloc(TMPBUFSIZE)) == NULL) sl@0: { sl@0: listDestroyList((*handle)->mem); sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: return MP4_OUT_OF_MEMORY; sl@0: } sl@0: sl@0: if (((*handle)->diskReadBuf = (mp4_u8 *)mp4malloc(READBUFSIZE)) == NULL) sl@0: { sl@0: mp4free((*handle)->buf); sl@0: listDestroyList((*handle)->mem); sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: return MP4_OUT_OF_MEMORY; sl@0: } sl@0: sl@0: // register for stblib use sl@0: if (openStdlib() != MP4_OK) sl@0: { sl@0: // clean up sl@0: mp4free((*handle)->diskReadBuf); sl@0: mp4free((*handle)->buf); sl@0: listDestroyList((*handle)->mem); sl@0: closeFile(*handle); sl@0: mp4free(*handle); sl@0: *handle = NULL; sl@0: sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseClose(MP4Handle apihandle) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->file) sl@0: closeFile(handle); sl@0: sl@0: closeStdlib(); /* Free memory allocated by stdlib wrapper functions */ sl@0: sl@0: listDestroyList(handle->mem); sl@0: sl@0: if (handle->diskReadBuf) sl@0: mp4free(handle->diskReadBuf); sl@0: sl@0: if (handle->buf) sl@0: mp4free(handle->buf); sl@0: sl@0: if (freeMOOV(handle->moov) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (freeFTYP(handle->ftyp) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->file32Duplicate) sl@0: ((RFile64*)handle->file32Duplicate)->Close(); sl@0: sl@0: if (handle) sl@0: mp4free(handle); sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseRequestVideoDescription(MP4Handle apihandle, sl@0: mp4_u32 *videolength, sl@0: mp4_double *framerate, sl@0: mp4_u32 *videotype, sl@0: mp4_u32 *videowidth, sl@0: mp4_u32 *videoheight, sl@0: mp4_u32 *timescale) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo) sl@0: return MP4_NO_VIDEO; sl@0: sl@0: mp4_i32 videoError = 0; sl@0: videoError = determineVideoType(handle, videotype); sl@0: if ( videoError == -2 ) sl@0: { sl@0: return MP4_NO_VIDEO; sl@0: } sl@0: else if ( videoError < 0 ) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (determineVideoLength(handle, videolength) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (determineFrameRate(handle, framerate) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (determineVideoResolution(handle, videowidth, videoheight) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (determineVideoTimeScale(handle, timescale) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseRequestAudioDescription(MP4Handle apihandle, sl@0: mp4_u32 *audiolength, sl@0: mp4_u32 *audiotype, sl@0: mp4_u8 *framespersample, sl@0: mp4_u32 *timescale, sl@0: mp4_u32 *averagebitrate) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakAudio) sl@0: return MP4_NO_AUDIO; sl@0: sl@0: if (determineAudioLength(handle, audiolength) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: mp4_i32 audioError = 0; sl@0: audioError = determineAudioType(handle, audiotype); sl@0: if ( audioError == -2 ) sl@0: { sl@0: return MP4_NO_AUDIO; sl@0: } sl@0: else if ( audioError < 0 ) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (determineAudioFramesPerSample(handle, framespersample) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (determineAudioTimeScale(handle, timescale) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (averagebitrate != NULL) sl@0: if (determineAudioAverageBitRate(handle, averagebitrate) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseRequestStreamDescription(MP4Handle apihandle, sl@0: mp4_u32 *streamsize, sl@0: mp4_u32 *streamaveragebitrate) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (determineStreamSize(handle, streamsize) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (determineStreamAverageBitRate(handle, streamaveragebitrate, *streamsize) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseWriteData(MP4Handle apihandle, sl@0: mp4_u8 *buffer, sl@0: mp4_u32 bytestowrite) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (handle->file) sl@0: return MP4_ERROR; sl@0: sl@0: if ((buffer == NULL) && (bytestowrite != 0)) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->LastWriteDataCalled == MP4TRUE) sl@0: return MP4_ERROR; // WriteData() call has been made before with bytestowrite=0, can not call again. sl@0: sl@0: if (bytestowrite != 0) sl@0: { sl@0: if (addData(handle, buffer, bytestowrite) == -1) sl@0: return MP4_OUT_OF_MEMORY; sl@0: } sl@0: else sl@0: handle->LastWriteDataCalled = MP4TRUE; sl@0: sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetBufferedBytes(MP4Handle apihandle, sl@0: mp4_u32 *bytes) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: *bytes = getBufferedBytes(handle); sl@0: sl@0: if (handle->file) sl@0: return MP4_FILE_MODE; sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseNextFrameType(MP4Handle apihandle, sl@0: mp4_u32 *type) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: /* No audio nor video */ sl@0: if ((!handle->moov->trakAudio) && (!handle->moov->trakVideo)) sl@0: return MP4_ERROR; sl@0: sl@0: mp4_u32 audiotype = 0; sl@0: mp4_i32 audioerror = 0; sl@0: if (handle->moov->trakAudio) sl@0: { sl@0: audioerror = determineAudioType(handle, &audiotype); sl@0: } sl@0: sl@0: mp4_u32 videotype = 0; sl@0: mp4_i32 videoerror = 0; sl@0: if (handle->moov->trakVideo) sl@0: { sl@0: videoerror = determineVideoType(handle, &videotype); sl@0: } sl@0: sl@0: /* Audio track only */ sl@0: if (handle->moov->trakAudio && !handle->moov->trakVideo) sl@0: { sl@0: if (audioerror == 0) sl@0: { sl@0: // if audio is of supported type, check if the last audio frame has been sl@0: // retrieved sl@0: if (handle->audioLast) sl@0: { sl@0: return MP4_NO_FRAME; sl@0: } sl@0: else sl@0: { sl@0: *type = audiotype; sl@0: return MP4_OK; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: /* Video track only */ sl@0: if (handle->moov->trakVideo && !handle->moov->trakAudio) sl@0: { sl@0: if (videoerror == 0) sl@0: { sl@0: // if video is of supported type, check if the last video frame has been sl@0: // retrieved sl@0: if (handle->videoLast) sl@0: { sl@0: return MP4_NO_FRAME; sl@0: } sl@0: else sl@0: { sl@0: *type = videotype; sl@0: return MP4_OK; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: /* All audio has been read, but there is video left */ sl@0: if (handle->audioLast && !handle->videoLast) sl@0: { sl@0: if (videoerror == 0) sl@0: { sl@0: *type = videotype; sl@0: return MP4_OK; sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: /* All video has been read, but there is audio left */ sl@0: if (handle->videoLast && !handle->audioLast) sl@0: { sl@0: if (audioerror == 0) sl@0: { sl@0: *type = audiotype; sl@0: return MP4_OK; sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: /* All data has been read */ sl@0: if (handle->audioLast && handle->videoLast) sl@0: { sl@0: return MP4_NO_FRAME; sl@0: } sl@0: sl@0: if (handle->audioSampleOffset < handle->videoFrameOffset) sl@0: { sl@0: /* Next frame is audio */ sl@0: if (audioerror == 0) sl@0: { sl@0: *type = audiotype; sl@0: return MP4_OK; sl@0: } sl@0: else if ( (audioerror == -2) && (videoerror == 0) ) sl@0: { sl@0: *type = videotype; sl@0: return MP4_OK; sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: /* Next frame is video */ sl@0: if (videoerror == 0) sl@0: { sl@0: *type = videotype; sl@0: return MP4_OK; sl@0: } sl@0: else if ( (videoerror == -2) && (audioerror == 0) ) sl@0: { sl@0: *type = audiotype; sl@0: return MP4_OK; sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseNextFrameSize(MP4Handle apihandle, sl@0: mp4_u32 type, sl@0: mp4_u32 *framesize) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: switch (type & handle->type) sl@0: { sl@0: case MP4_TYPE_MPEG4_VIDEO: sl@0: case MP4_TYPE_H263_PROFILE_0: sl@0: case MP4_TYPE_H263_PROFILE_3: sl@0: case MP4_TYPE_AVC_PROFILE_BASELINE: sl@0: case MP4_TYPE_AVC_PROFILE_MAIN: sl@0: case MP4_TYPE_AVC_PROFILE_EXTENDED: sl@0: case MP4_TYPE_AVC_PROFILE_HIGH: sl@0: sl@0: /* There is a next video frame */ sl@0: sl@0: if (!handle->videoLast) sl@0: *framesize = handle->videoFrameSize; sl@0: else sl@0: { sl@0: *framesize = 0; sl@0: sl@0: return MP4_NO_REQUESTED_FRAME; sl@0: } sl@0: sl@0: break; sl@0: sl@0: case MP4_TYPE_MPEG4_AUDIO: sl@0: case MP4_TYPE_AMR_NB: sl@0: case MP4_TYPE_AMR_WB: sl@0: case MP4_TYPE_QCELP_13K: sl@0: sl@0: /* There is a next audio frame */ sl@0: sl@0: if (!handle->audioLast) sl@0: *framesize = handle->audioSampleSize; sl@0: else sl@0: { sl@0: *framesize = 0; sl@0: sl@0: return MP4_NO_REQUESTED_FRAME; sl@0: } sl@0: sl@0: break; sl@0: sl@0: case MP4_TYPE_NONE: sl@0: default: sl@0: sl@0: if (type == MP4_TYPE_MPEG4_VIDEO || sl@0: type == MP4_TYPE_H263_PROFILE_0 || sl@0: type == MP4_TYPE_H263_PROFILE_3 || sl@0: type == MP4_TYPE_MPEG4_AUDIO || sl@0: type == MP4_TYPE_AMR_NB || sl@0: type == MP4_TYPE_AMR_WB || sl@0: isAvcVideo(type) || sl@0: type == MP4_TYPE_QCELP_13K sl@0: ) sl@0: return MP4_NO_REQUESTED_FRAME; sl@0: sl@0: return MP4_INVALID_TYPE; sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseReadVideoFrame(MP4Handle apihandle, sl@0: mp4_u8 *buffer, sl@0: mp4_u32 buffersize, sl@0: mp4_u32 *framesize, sl@0: mp4_u32 *timestamp, sl@0: mp4_bool *keyframe, sl@0: mp4_u32 *timestamp2) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: /* Is video available? */ sl@0: sl@0: if (!((handle->type & MP4_TYPE_MPEG4_VIDEO) || sl@0: (handle->type & MP4_TYPE_H263_PROFILE_0) || sl@0: (handle->type & MP4_TYPE_H263_PROFILE_3) || sl@0: containsAvcVideo( handle->type ) )) sl@0: return MP4_ERROR; sl@0: sl@0: /* Are there samples left? */ sl@0: sl@0: if (handle->videoLast) sl@0: return MP4_NO_FRAME; sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo) sl@0: return MP4_ERROR; sl@0: sl@0: switch (fetchVideoFrame(handle, handle->moov->trakVideo, buffer, buffersize, framesize, timestamp, keyframe, timestamp2)) sl@0: { sl@0: case -1: sl@0: return MP4_ERROR; sl@0: case -2: sl@0: return MP4_BUFFER_TOO_SMALL; sl@0: case -3: sl@0: return MP4_NOT_AVAILABLE; sl@0: case -4: sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: default: sl@0: break; sl@0: } sl@0: sl@0: switch (advanceVideoFrame(handle, handle->moov->trakVideo)) sl@0: { sl@0: case -1: sl@0: return MP4_ERROR; sl@0: case -2: sl@0: handle->videoLast = MP4TRUE; sl@0: break; sl@0: default: sl@0: break; sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseReadVideoDecoderSpecificInfo(MP4Handle apihandle, sl@0: mp4_u8 *buffer, sl@0: mp4_u32 buffersize, sl@0: mp4_u32 *decspecinfosize) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: /* Is video type MPEG or AVC? */ sl@0: if (!(handle->type & MP4_TYPE_MPEG4_VIDEO) && sl@0: !(containsAvcVideo( handle->type )) ) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakVideo) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakVideo->mdia) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakVideo->mdia->minf) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stsd) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (handle->videoSampleEntryIndex > handle->moov->trakVideo->mdia->minf->stbl->stsd->entryCount) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: TInt index = handle->videoSampleEntryIndex - 1; sl@0: if (handle->videoSampleEntryIndex == 0) sl@0: { sl@0: // even though the video sample contains no actual data, if the video sample exist sl@0: // and contains decoder specific info, return it anyway sl@0: index = 0; sl@0: } sl@0: sl@0: if (handle->type & MP4_TYPE_MPEG4_VIDEO) sl@0: { sl@0: /* Copy DecoderSpecificInfo into buffer */ sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[index]) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[index]->esd) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: *decspecinfosize = handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[index]->esd->decSpecificInfoSize; sl@0: if (buffersize < handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[index]->esd->decSpecificInfoSize) sl@0: { sl@0: return MP4_BUFFER_TOO_SMALL; sl@0: } sl@0: sl@0: mp4memcpy(buffer, sl@0: handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[index]->esd->decSpecificInfo, sl@0: handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[index]->esd->decSpecificInfoSize); sl@0: } sl@0: else if ( containsAvcVideo( handle->type ) ) sl@0: { sl@0: /* Copy the AVCDecoderConfigurationRecord into buffer */ sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[index]) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[index]->avcc) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: *decspecinfosize = handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[index]->avcc->avcConfigSize; sl@0: if (buffersize < handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[index]->avcc->avcConfigSize) sl@0: { sl@0: return MP4_BUFFER_TOO_SMALL; sl@0: } sl@0: sl@0: mp4memcpy(buffer, sl@0: handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[index]->avcc->avcConfig, sl@0: handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[index]->avcc->avcConfigSize); sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseReadAudioFrames(MP4Handle apihandle, sl@0: mp4_u8 *buffer, sl@0: mp4_u32 buffersize, sl@0: mp4_u32 *audiosize, sl@0: mp4_u32 *timestamp, sl@0: mp4_u32 *returnedframes, sl@0: mp4_u32 *timestamp2) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: /* Is audio available? */ sl@0: sl@0: if (!((handle->type & MP4_TYPE_MPEG4_AUDIO) || sl@0: (handle->type & MP4_TYPE_AMR_NB) || sl@0: (handle->type & MP4_TYPE_AMR_WB) || sl@0: (handle->type & MP4_TYPE_QCELP_13K))) sl@0: return MP4_ERROR; sl@0: sl@0: /* Are there samples left? */ sl@0: sl@0: if (handle->audioLast) sl@0: return MP4_NO_FRAME; sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakAudio) sl@0: return MP4_ERROR; sl@0: sl@0: switch (fetchAudioSample(handle, handle->moov->trakAudio, buffer, buffersize, audiosize, timestamp, returnedframes, timestamp2)) sl@0: { sl@0: case -1: sl@0: return MP4_ERROR; sl@0: case -2: sl@0: return MP4_BUFFER_TOO_SMALL; sl@0: case -3: sl@0: return MP4_NOT_AVAILABLE; sl@0: case -4: sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: default: sl@0: break; sl@0: } sl@0: sl@0: switch (advanceAudioSample(handle, handle->moov->trakAudio)) sl@0: { sl@0: case -1: sl@0: return MP4_ERROR; sl@0: case -2: sl@0: handle->audioLast = MP4TRUE; sl@0: break; sl@0: default: sl@0: break; sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseReadAudioDecoderSpecificInfo(MP4Handle apihandle, sl@0: mp4_u8 *buffer, sl@0: mp4_u32 buffersize, sl@0: mp4_u32 *decspecinfosize) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakAudio) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakAudio->mdia) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakAudio->mdia->minf) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakAudio->mdia->minf->stbl) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakAudio->mdia->minf->stbl->stsd) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: sl@0: TInt index = handle->audioSampleEntryIndex - 1; sl@0: if (handle->audioSampleEntryIndex == 0) sl@0: { sl@0: // even though the audio sample contains no actual data, if the audio sample exist sl@0: // and contains decoder specific info, return it anyway sl@0: index = 0; sl@0: } sl@0: sl@0: /* Audio type */ sl@0: if ((handle->type & MP4_TYPE_MPEG4_AUDIO) || sl@0: ((handle->type & MP4_TYPE_QCELP_13K) && (handle->qcelpStoredAsMPEGAudio))) sl@0: { sl@0: /* Copy DecoderSpecificInfo into buffer */ sl@0: if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[index]) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[index]->esd) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: *decspecinfosize = handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[index]->esd->decSpecificInfoSize; sl@0: if (buffersize < handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[index]->esd->decSpecificInfoSize) sl@0: { sl@0: return MP4_BUFFER_TOO_SMALL; sl@0: } sl@0: sl@0: mp4memcpy(buffer, sl@0: handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[index]->esd->decSpecificInfo, sl@0: handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[index]->esd->decSpecificInfoSize); sl@0: } sl@0: else if ((handle->type & MP4_TYPE_AMR_NB) || sl@0: (handle->type & MP4_TYPE_AMR_WB) || sl@0: ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio))) sl@0: { sl@0: /* Copy DecoderSpecificInfo into buffer */ sl@0: if (handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index] == NULL && sl@0: handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index] == NULL && sl@0: handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[index] == NULL) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]) sl@0: { sl@0: if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]->damr) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: *decspecinfosize = 9; sl@0: if (buffersize < *decspecinfosize) sl@0: { sl@0: return MP4_BUFFER_TOO_SMALL; sl@0: } sl@0: sl@0: mp4memcpy(buffer, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]->damr->vendor), 4); sl@0: mp4memcpy(buffer+4, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]->damr->decoderVersion), 1); sl@0: mp4memcpy(buffer+5, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]->damr->modeSet), 2); sl@0: mp4memcpy(buffer+7, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]->damr->modeChangePeriod), 1); sl@0: mp4memcpy(buffer+8, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]->damr->framesPerSample), 1); sl@0: } sl@0: sl@0: if (handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]) sl@0: { sl@0: if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]->damr) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: *decspecinfosize = 9; sl@0: if (buffersize < *decspecinfosize) sl@0: { sl@0: return MP4_BUFFER_TOO_SMALL; sl@0: } sl@0: sl@0: mp4memcpy(buffer, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]->damr->vendor), 4); sl@0: mp4memcpy(buffer+4, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]->damr->decoderVersion), 1); sl@0: mp4memcpy(buffer+5, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]->damr->modeSet), 2); sl@0: mp4memcpy(buffer+7, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]->damr->modeChangePeriod), 1); sl@0: mp4memcpy(buffer+8, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]->damr->framesPerSample), 1); sl@0: } sl@0: sl@0: if (handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[index]) sl@0: { sl@0: if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[index]->dqcp) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: *decspecinfosize = 6; sl@0: if (buffersize < *decspecinfosize) sl@0: { sl@0: return MP4_BUFFER_TOO_SMALL; sl@0: } sl@0: sl@0: mp4memcpy(buffer, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[index]->dqcp->vendor), 4); sl@0: mp4memcpy(buffer+4, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[index]->dqcp->decoderVersion), 1); sl@0: mp4memcpy(buffer+5, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[index]->dqcp->framesPerSample), 1); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetNextVideoTimestamp(MP4Handle apihandle, sl@0: mp4_u32 *timestamp, sl@0: mp4_u32 *timestamp2) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->videoLast) sl@0: return MP4_END_OF_VIDEO; sl@0: sl@0: if (convertVideoSampleToTime(handle, handle->moov->trakVideo->mdia, timestamp, timestamp2) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: switch (advanceVideoFrame(handle, handle->moov->trakVideo)) sl@0: { sl@0: case -1: sl@0: return MP4_ERROR; sl@0: case -2: sl@0: handle->videoLast = MP4TRUE; sl@0: break; sl@0: default: sl@0: break; sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseIsStreamable(MP4Handle apihandle) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: /* There is no audio nor video */ sl@0: sl@0: if (!handle->audioSampleNum && !handle->videoSampleNum) sl@0: return MP4_ERROR; sl@0: sl@0: /* There is audio, but no video */ sl@0: sl@0: if (handle->audioSampleNum && !handle->videoSampleNum) sl@0: { sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakAudio) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakAudio->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakAudio->mdia->minf) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakAudio->mdia->minf->stbl) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakAudio->mdia->minf->stbl->stco) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->moov->trakAudio->mdia->minf->stbl->stco->entryCount < 2) sl@0: return MP4_OK; sl@0: sl@0: if (getChunkOffset(handle->moov->trakAudio->mdia->minf->stbl, 0) < sl@0: getChunkOffset(handle->moov->trakAudio->mdia->minf->stbl, 1)) sl@0: return MP4_OK; sl@0: sl@0: return MP4_NOT_STREAMABLE; sl@0: } sl@0: sl@0: /* There is video, but no audio */ sl@0: sl@0: if (handle->videoSampleNum && !handle->audioSampleNum) sl@0: { sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stco) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->moov->trakVideo->mdia->minf->stbl->stco->entryCount < 2) sl@0: return MP4_OK; sl@0: sl@0: if (getChunkOffset(handle->moov->trakVideo->mdia->minf->stbl, 0) < sl@0: getChunkOffset(handle->moov->trakVideo->mdia->minf->stbl, 1)) sl@0: return MP4_OK; sl@0: sl@0: return MP4_NOT_STREAMABLE; sl@0: } sl@0: sl@0: /* There are both audio and video */ sl@0: sl@0: if (handle->videoSampleNum && handle->audioSampleNum) sl@0: { sl@0: mp4_i64 diff; sl@0: sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakAudio) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakAudio->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakAudio->mdia->minf) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakAudio->mdia->minf->stbl) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakAudio->mdia->minf->stbl->stco) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakAudio->mdia->minf->stbl->stco->entryCount) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stco) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stco->entryCount) sl@0: return MP4_ERROR; sl@0: sl@0: diff = getChunkOffset(handle->moov->trakAudio->mdia->minf->stbl, 0) - sl@0: getChunkOffset(handle->moov->trakVideo->mdia->minf->stbl, 0); sl@0: sl@0: /* If the distance between 1st audio and video chunk offsets is larger sl@0: than 50000, MP4 is not streamable. */ sl@0: sl@0: if (diff < -50000 || diff > 50000) sl@0: return MP4_NOT_STREAMABLE; sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseSeek(MP4Handle apihandle, sl@0: mp4_u32 position, sl@0: mp4_u32 *audioPosition, sl@0: mp4_u32 *videoPosition, sl@0: mp4_bool keyframe) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: {// if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: sl@0: handle->audioLast = MP4FALSE; sl@0: handle->videoLast = MP4FALSE; sl@0: sl@0: /* There is no audio nor video */ sl@0: sl@0: if (!handle->audioSampleNum && !handle->videoSampleNum) sl@0: return MP4_ERROR; sl@0: sl@0: /* There is only audio */ sl@0: sl@0: if (handle->audioSampleNum && !handle->videoSampleNum) sl@0: { sl@0: mp4_u32 audioSample; sl@0: sl@0: if (!handle->moov->trakAudio) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakAudio->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (convertTimeToSample(handle, handle->moov->trakAudio, position, &audioSample) < 0) sl@0: return MP4_CANT_SEEK; sl@0: sl@0: if (goToAudioSample(handle, handle->moov->trakAudio, audioSample) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (convertAudioSampleToTime(handle, handle->moov->trakAudio->mdia, audioPosition, NULL) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->file) sl@0: { sl@0: handle->lastAccessedPosInFile = handle->audioSampleOffset + handle->audioSampleSize - 1; sl@0: } sl@0: else sl@0: { sl@0: // check if there is enough data in the buffers sl@0: if (handle->audioSampleOffset + handle->audioSampleSize - 1 > getCumulativeBufferedBytes(handle)) sl@0: { sl@0: if (handle->LastWriteDataCalled) sl@0: { sl@0: // user has indicated that no more data will be available sl@0: return MP4_CANT_SEEK; sl@0: } sl@0: else sl@0: { sl@0: // signal to user that more data needed sl@0: return MP4_NOT_AVAILABLE; sl@0: } sl@0: } sl@0: else if (handle->audioSampleOffset < handle->absPosition) sl@0: { sl@0: handle->absPosition = handle->audioSampleOffset; sl@0: } sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: /* There is only video */ sl@0: if (handle->videoSampleNum && !handle->audioSampleNum) sl@0: { sl@0: mp4_u32 videoSample; sl@0: mp4_u32 newVideoSample; sl@0: sl@0: if (!handle->moov->trakVideo) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (convertTimeToSample(handle, handle->moov->trakVideo, position, &videoSample) < 0) sl@0: return MP4_CANT_SEEK; sl@0: sl@0: if (keyframe) sl@0: { sl@0: if (findVideoKeyFrame(handle, handle->moov->trakVideo, videoSample, &newVideoSample) < 0) sl@0: { sl@0: return MP4_CANT_SEEK; sl@0: } sl@0: videoSample = newVideoSample; sl@0: } sl@0: sl@0: if (goToVideoSample(handle, handle->moov->trakVideo, videoSample) < 0) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (convertVideoSampleToTime(handle, handle->moov->trakVideo->mdia, videoPosition, NULL) < 0) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (handle->file) sl@0: { sl@0: handle->lastAccessedPosInFile = handle->videoFrameOffset + handle->videoFrameSize - 1; sl@0: } sl@0: else // input is a stream sl@0: { sl@0: // check if there is enough data in the buffers sl@0: if (handle->videoFrameOffset + handle->videoFrameSize > getCumulativeBufferedBytes(handle)) sl@0: { sl@0: if (handle->LastWriteDataCalled) sl@0: { sl@0: // user has indicated that no more data will be available sl@0: return MP4_CANT_SEEK; sl@0: } sl@0: else sl@0: { sl@0: // signal to user that more data needed sl@0: return MP4_NOT_AVAILABLE; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: handle->absPosition = handle->videoFrameOffset; sl@0: } sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: /* There is audio and video */ sl@0: sl@0: if (handle->videoSampleNum && handle->audioSampleNum) sl@0: { sl@0: mp4_u32 audioSample; sl@0: mp4_u32 videoSample; sl@0: mp4_u32 newVideoSample; sl@0: sl@0: sl@0: if (!handle->moov->trakAudio) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakAudio->mdia) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (convertTimeToSample(handle, handle->moov->trakVideo, position, &videoSample) < 0) sl@0: return MP4_CANT_SEEK; sl@0: sl@0: if (keyframe) sl@0: { sl@0: if (findVideoKeyFrame(handle, handle->moov->trakVideo, videoSample, &newVideoSample) < 0) sl@0: return MP4_CANT_SEEK; sl@0: sl@0: videoSample = newVideoSample; sl@0: } sl@0: sl@0: if (goToVideoSample(handle, handle->moov->trakVideo, videoSample) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (convertVideoSampleToTime(handle, handle->moov->trakVideo->mdia, videoPosition, NULL) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->file) sl@0: { sl@0: handle->lastAccessedPosInFile = handle->videoFrameOffset + handle->videoFrameSize - 1; sl@0: } sl@0: else // input is a stream sl@0: { sl@0: // check if there is enough data in the buffers sl@0: if (handle->videoFrameOffset + handle->videoFrameSize > getCumulativeBufferedBytes(handle)) sl@0: { sl@0: if (handle->LastWriteDataCalled) sl@0: { sl@0: // user has indicated that no more data will be available sl@0: return MP4_CANT_SEEK; sl@0: } sl@0: else sl@0: { sl@0: // signal to user that more data needed sl@0: return MP4_NOT_AVAILABLE; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: handle->absPosition = handle->videoFrameOffset; sl@0: } sl@0: } sl@0: sl@0: /* Audio */ sl@0: sl@0: if (convertTimeToSample(handle, handle->moov->trakAudio, *videoPosition, &audioSample) < 0) sl@0: return MP4_CANT_SEEK; sl@0: sl@0: if (goToAudioSample(handle, handle->moov->trakAudio, audioSample) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (convertAudioSampleToTime(handle, handle->moov->trakAudio->mdia, audioPosition, NULL) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->file) sl@0: { sl@0: if (handle->audioSampleOffset + handle->audioSampleSize - 1 > handle->lastAccessedPosInFile) sl@0: { sl@0: handle->lastAccessedPosInFile = handle->audioSampleOffset + handle->audioSampleSize - 1; sl@0: } sl@0: } sl@0: else // input is a stream sl@0: { sl@0: // check if there is enough data in the buffers sl@0: if (handle->audioSampleOffset + handle->audioSampleSize - 1 > getCumulativeBufferedBytes(handle)) sl@0: { sl@0: if (handle->LastWriteDataCalled) sl@0: { sl@0: // user has indicated that no more data will be available sl@0: return MP4_CANT_SEEK; sl@0: } sl@0: else sl@0: { sl@0: // signal to user that more data needed sl@0: return MP4_NOT_AVAILABLE; sl@0: } sl@0: } sl@0: else if (handle->audioSampleOffset < handle->absPosition) sl@0: { sl@0: handle->absPosition = handle->audioSampleOffset; sl@0: } sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseIsFrameAvailable(MP4Handle apihandle, sl@0: mp4_u32 type) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: switch (type & handle->type) sl@0: { sl@0: case MP4_TYPE_MPEG4_VIDEO: sl@0: case MP4_TYPE_H263_PROFILE_0: sl@0: case MP4_TYPE_H263_PROFILE_3: sl@0: case MP4_TYPE_AVC_PROFILE_BASELINE: sl@0: case MP4_TYPE_AVC_PROFILE_MAIN: sl@0: case MP4_TYPE_AVC_PROFILE_EXTENDED: sl@0: case MP4_TYPE_AVC_PROFILE_HIGH: sl@0: sl@0: /* There is no frame available if last sample has been reached */ sl@0: sl@0: if (handle->videoLast) sl@0: return MP4_NO_REQUESTED_FRAME; sl@0: sl@0: /* Input in a file => it is available */ sl@0: sl@0: if (handle->file) sl@0: return MP4_OK; sl@0: sl@0: /* If frame has been buffered, it is available */ sl@0: sl@0: if (handle->videoFrameOffset + handle->videoFrameSize <= sl@0: getCumulativeBufferedBytes(handle)) sl@0: return MP4_OK; sl@0: else sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case MP4_TYPE_MPEG4_AUDIO: sl@0: case MP4_TYPE_AMR_NB: sl@0: case MP4_TYPE_AMR_WB: sl@0: case MP4_TYPE_QCELP_13K: sl@0: sl@0: /* There is no frame available if last sample has been reached */ sl@0: sl@0: if (handle->audioLast) sl@0: return MP4_NO_REQUESTED_FRAME; sl@0: sl@0: /* Input in a file => it is available */ sl@0: sl@0: if (handle->file) sl@0: return MP4_OK; sl@0: sl@0: /* If frame has been buffered, it is available */ sl@0: sl@0: if (handle->audioSampleOffset + handle->audioSampleSize <= sl@0: getCumulativeBufferedBytes(handle)) sl@0: return MP4_OK; sl@0: else sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case MP4_TYPE_NONE: sl@0: default: sl@0: sl@0: return MP4_NO_REQUESTED_FRAME; sl@0: } sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetLastPosition(MP4Handle apihandle, sl@0: mp4_u32 *position) sl@0: { sl@0: return MP4ParseGetLastPosition64(apihandle, (mp4_u64 *)position); sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetLastPosition64(MP4Handle apihandle, sl@0: mp4_u64 *position) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle->file) sl@0: { sl@0: *position = handle->absPosition; // return the latest accessed absolute byte location of the stream. sl@0: return MP4_OK; sl@0: } sl@0: *position = handle->lastAccessedPosInFile; sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetNumberOfVideoFrames(MP4Handle apihandle, sl@0: mp4_u32 *numberOfFrames) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: {// if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->moov->trakVideo) sl@0: { sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stsz) sl@0: return MP4_ERROR; sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: *numberOfFrames = handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount; sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetVideoFrameSize(MP4Handle apihandle, sl@0: mp4_u32 index, sl@0: mp4_u32 *frameSize) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: {// if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->moov->trakVideo) sl@0: { sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stsz) sl@0: return MP4_ERROR; sl@0: sl@0: // ensure the index entered is within bound sl@0: if (index >= handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount) sl@0: return MP4_ERROR; sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: *frameSize = handle->moov->trakVideo->mdia->minf->stbl->stsz->entrySize[index]; sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetVideoFrameStartTime(MP4Handle apihandle, sl@0: mp4_u32 index, sl@0: mp4_u32 *timestamp, sl@0: mp4_u32 *timestampms) sl@0: { sl@0: mp4_u32 tmptime=0; sl@0: mp4_u32 sample=0; sl@0: mp4_u32 entry=0; sl@0: mp4_u32 videoSampleNumber = index+1; sl@0: sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: {// if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (handle->moov->trakVideo) sl@0: { sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stts) sl@0: return MP4_ERROR; sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: for (;;) sl@0: { sl@0: if (sample + handle->moov->trakVideo->mdia->minf->stbl->stts->sampleCount[entry] < videoSampleNumber) sl@0: { sl@0: sample += handle->moov->trakVideo->mdia->minf->stbl->stts->sampleCount[entry]; sl@0: tmptime += (handle->moov->trakVideo->mdia->minf->stbl->stts->sampleCount[entry] * sl@0: handle->moov->trakVideo->mdia->minf->stbl->stts->sampleDelta[entry]); sl@0: entry++; sl@0: if (entry == handle->moov->trakVideo->mdia->minf->stbl->stts->entryCount) sl@0: return MP4_ERROR; sl@0: } sl@0: else sl@0: { sl@0: tmptime += ((videoSampleNumber - sample - 1) * handle->moov->trakVideo->mdia->minf->stbl->stts->sampleDelta[entry]); sl@0: break; sl@0: } sl@0: } sl@0: if (handle->moov->trakVideo->mdia->mdhd->timeScale == 0) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: *timestamp = tmptime; sl@0: sl@0: *timestampms =(mp4_u32)((mp4_double)tmptime * (mp4_double)1000 / sl@0: (mp4_double)handle->moov->trakVideo->mdia->mdhd->timeScale + (mp4_double)0.5); sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetVideoFrameType(MP4Handle apihandle, sl@0: mp4_u32 index, sl@0: mp4_bool *frametype) sl@0: { sl@0: mp4_u32 i; sl@0: mp4_u32 videoSampleNumber = index+1; sl@0: mp4_bool keyFrame = MP4FALSE; sl@0: sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: {// if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->moov->trakVideo) sl@0: { sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stss) sl@0: return MP4_ERROR; sl@0: sl@0: // if the video frame index is out of bounds sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stsz || sl@0: videoSampleNumber > handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount) sl@0: return MP4_ERROR; sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: for (i=0; i < handle->moov->trakVideo->mdia->minf->stbl->stss->entryCount; i++) sl@0: { sl@0: if (handle->moov->trakVideo->mdia->minf->stbl->stss->sampleNumber[i] == videoSampleNumber) sl@0: { sl@0: keyFrame = MP4TRUE; sl@0: break; sl@0: } sl@0: } sl@0: sl@0: *frametype = keyFrame; sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetVideoSampleEntryIndex(MP4Handle apihandle, mp4_u32 *videosampleentryindex) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: {// if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov->trakVideo) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->videoSampleEntryIndex == 0) /* can't be zero. Sample Entry index must be at least 1*/ sl@0: return MP4_ERROR; sl@0: else sl@0: *videosampleentryindex = handle->videoSampleEntryIndex; sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetAudioSampleEntryIndex(MP4Handle apihandle, mp4_u32 *audiosampleentryindex) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: {// if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov->trakAudio) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakAudio->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->audioSampleEntryIndex == 0) /* can't be zero. Sample Entry index must be at least 1*/ sl@0: return MP4_ERROR; sl@0: else sl@0: *audiosampleentryindex = handle->audioSampleEntryIndex; sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetQCELPStorageMode(MP4Handle apihandle, mp4_u8 *qcelpStorageMode) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: {// if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov->trakAudio) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakAudio->mdia) sl@0: return MP4_ERROR; sl@0: if (!(handle->type & MP4_TYPE_QCELP_13K)) sl@0: return MP4_ERROR; sl@0: sl@0: if(handle->qcelpStoredAsMPEGAudio) sl@0: *qcelpStorageMode = 1; sl@0: else sl@0: *qcelpStorageMode = 0; sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4GetVideoFrameProperties(MP4Handle apihandle,mp4_u32 startindex,mp4_u32 sizeofarray,TFrameInfoParameters* aFrameInfoArray) sl@0: { sl@0: sl@0: mp4_u32 tmptime=0; sl@0: mp4_u32 sample=0; sl@0: mp4_u32 entry=0; sl@0: mp4_u32 videoSampleNumber = (startindex+sizeofarray)+1; sl@0: mp4_u32 i; sl@0: mp4_u32 j; sl@0: mp4_u32 index; sl@0: mp4_u32 actualIndex; sl@0: sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: TBool sampleSyncTableExists = ETrue; sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: {// if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->moov->trakVideo) sl@0: { sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl) sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stsz) //for size sl@0: return MP4_ERROR; sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stss) //for type sl@0: { sl@0: // If sample sync table doesn't exist mark all frames as intra / random access point sl@0: sampleSyncTableExists = EFalse; sl@0: } sl@0: sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stts) //For timeStamp sl@0: return MP4_ERROR; sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: sl@0: if (handle->moov->trakVideo->mdia->mdhd->timeScale == 0) //For timeStamp sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if((startindex+sizeofarray) > handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount) //more than number of frames sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if(aFrameInfoArray == NULL) sl@0: { sl@0: return MP4_NO_OUTPUT_BUFFER; sl@0: } sl@0: sl@0: if ( sampleSyncTableExists ) sl@0: { sl@0: for (i=0; i < handle->moov->trakVideo->mdia->minf->stbl->stss->entryCount; i++) //set all types to true sl@0: { sl@0: //because counting is stored from 1 but index from 0 sl@0: mp4_u32 currFrame = handle->moov->trakVideo->mdia->minf->stbl->stss->sampleNumber[i] - 1; sl@0: sl@0: if ((currFrame >= startindex) && (currFrame < (startindex + sizeofarray))) sl@0: { sl@0: aFrameInfoArray[currFrame - startindex].iType = MP4TRUE; sl@0: } sl@0: } sl@0: } sl@0: sl@0: index=0; //initialize to beginning sl@0: actualIndex=0;//array indexer sl@0: sl@0: for(;;) sl@0: { sl@0: if(index< videoSampleNumber) sl@0: { sl@0: for(j=0;jmoov->trakVideo->mdia->minf->stbl->stts->sampleCount[entry];j++) sl@0: { sl@0: if(index >=startindex) sl@0: { sl@0: //first initialize flag to false if not previously set to true. sl@0: if(aFrameInfoArray[actualIndex].iType != MP4TRUE) sl@0: { sl@0: aFrameInfoArray[actualIndex].iType = MP4FALSE; sl@0: } sl@0: //aFrameInfoArray[index].iStartTime = tmptime + handle->moov->trakVideo->mdia->minf->stbl->stts->sampleDelta[entry]; sl@0: if(index==0) //so first frame of entire clip sl@0: { sl@0: aFrameInfoArray[actualIndex].iStartTime =0; sl@0: } sl@0: else sl@0: { sl@0: aFrameInfoArray[actualIndex].iStartTime = (mp4_u32)((mp4_double)tmptime * (mp4_double)1000 / sl@0: (mp4_double)handle->moov->trakVideo->mdia->mdhd->timeScale + (mp4_double)0.5); sl@0: } sl@0: aFrameInfoArray[actualIndex].iSize = handle->moov->trakVideo->mdia->minf->stbl->stsz->entrySize[index]; sl@0: // If sample sync table doesn't exist mark all frames as intra / random access point sl@0: if (!sampleSyncTableExists) sl@0: { sl@0: aFrameInfoArray[actualIndex].iType = MP4TRUE; sl@0: } sl@0: actualIndex++; //point to next index in array sl@0: } sl@0: tmptime += handle->moov->trakVideo->mdia->minf->stbl->stts->sampleDelta[entry]; sl@0: //Now insert size before incrementing index sl@0: if(index == videoSampleNumber-2) sl@0: break; sl@0: index++; sl@0: } sl@0: if(index==videoSampleNumber-2) sl@0: break; sl@0: sample += handle->moov->trakVideo->mdia->minf->stbl->stts->sampleCount[entry]; sl@0: entry++; sl@0: } sl@0: else sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetVideoClipProperties(MP4Handle apihandle, TVideoClipProperties& aVideoClipProperties) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: if (!handle) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: {// if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo->mdia->minf) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stsd) sl@0: return MP4_ERROR; sl@0: sl@0: /* Assume that the video type is the same for all sample entries. Just get the video type from the first one */ sl@0: if (handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]) sl@0: { sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->d263) sl@0: return MP4_ERROR; sl@0: sl@0: if (handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->d263->h263Level) sl@0: { sl@0: aVideoClipProperties.iH263Level = handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->d263->h263Level; sl@0: return MP4_OK; sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetUserDataAtom(MP4Handle apihandle, sl@0: mp4_u8& udtaLocation, sl@0: mp4_u32 udtaAtomType, sl@0: mp4_u8* buffer, sl@0: mp4_u32& bufferSize, sl@0: mp4_u32& atomIndex ) sl@0: { sl@0: mp4_u32 size = 0; sl@0: mp4_u64 largesize = 0; sl@0: mp4_u32 type = 0; sl@0: mp4_i32 bytesread = 0; sl@0: mp4_i32 totalbytesread = 0; sl@0: MP4Err retError = MP4_OK; sl@0: userDataAtom* udta = NULL; sl@0: mp4_bool found = MP4FALSE; sl@0: mp4_u32 foundIndex = 0; sl@0: sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: {// if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: sl@0: // Check where to read udta from. sl@0: switch ( udtaLocation ) sl@0: { sl@0: case MP4_UDTA_NONE: sl@0: { sl@0: retError = MP4_UDTA_NOT_FOUND; sl@0: break; sl@0: } sl@0: case MP4_UDTA_MOOV: sl@0: { sl@0: if ( !handle->moov->udta ) sl@0: { sl@0: retError = MP4_UDTA_NOT_FOUND; sl@0: break; sl@0: } sl@0: else sl@0: { sl@0: udta = handle->moov->udta; sl@0: } sl@0: break; sl@0: } sl@0: case MP4_UDTA_VIDEOTRAK: sl@0: { sl@0: if ( !handle->moov->trakVideo ) sl@0: { sl@0: retError = MP4_UDTA_NOT_FOUND; sl@0: break; sl@0: } sl@0: if ( !handle->moov->trakVideo->udta ) sl@0: { sl@0: retError = MP4_UDTA_NOT_FOUND; sl@0: } sl@0: else sl@0: { sl@0: udta = handle->moov->trakVideo->udta; sl@0: } sl@0: break; sl@0: } sl@0: case MP4_UDTA_AUDIOTRAK: sl@0: { sl@0: if (!handle->moov->trakAudio) sl@0: { sl@0: retError = MP4_UDTA_NOT_FOUND; sl@0: break; sl@0: } sl@0: if ( !handle->moov->trakAudio->udta ) sl@0: { sl@0: retError = MP4_UDTA_NOT_FOUND; sl@0: } sl@0: else sl@0: { sl@0: udta = handle->moov->trakAudio->udta; sl@0: } sl@0: break; sl@0: } sl@0: default: sl@0: { sl@0: retError = MP4_INVALID_TYPE; sl@0: } sl@0: } sl@0: sl@0: if ( retError == MP4_OK ) // valid UDTA found. sl@0: { sl@0: if ( !udta->atomhdr ) sl@0: { sl@0: retError = MP4_UDTA_NOT_FOUND; sl@0: } sl@0: if ( !udta->atomcontentloc || (udta->atomcontentsize == 0) ) sl@0: { sl@0: retError = MP4_UDTA_NOT_FOUND; sl@0: } sl@0: sl@0: // seek to UDTA atom in memory structure or file. sl@0: if (handle->file) /* Input is in a file */ sl@0: { sl@0: if (seekFileAbs(handle, udta->atomcontentloc) != 0) sl@0: return MP4_CANT_SEEK; sl@0: } sl@0: else sl@0: { sl@0: handle->absPosition = udta->atomcontentloc; sl@0: } sl@0: sl@0: // search for wanted atom from UDTA and read it to buffer sl@0: while ( totalbytesread < (mp4_i32)udta->atomcontentsize ) sl@0: { sl@0: if (peekData(handle, handle->buf, 16) < 0) sl@0: return MP4_ERROR; sl@0: sl@0: size = u32endian(*((mp4_u32 *)handle->buf)); sl@0: type = u32endian(*((mp4_u32 *)(handle->buf+4))); sl@0: sl@0: if ( type == udtaAtomType ) sl@0: { sl@0: if ( atomIndex == foundIndex ) sl@0: { sl@0: if ( size == 1 ) sl@0: { sl@0: largesize = u64endian(*((mp4_u64*)(handle->buf+8))); sl@0: size = (mp4_u32)I64INT(largesize); sl@0: } sl@0: if ( size > bufferSize ) sl@0: { sl@0: // Although the output buffer supplied by the caller is sl@0: // not large enough to store the sub user atom's content, keep sl@0: // parsing thru the whole user data to retrieve the highest index sl@0: // to be returned thru the atomIndex parameter sl@0: bufferSize = size; sl@0: retError = MP4_OUTPUT_BUFFER_TOO_SMALL; sl@0: bytesread = readUnknown(handle); sl@0: if (bytesread < 0) sl@0: return MP4_ERROR; sl@0: } sl@0: else sl@0: { sl@0: bytesread = readData(handle, buffer, size); sl@0: if (bytesread < 0) sl@0: return MP4_ERROR; sl@0: bufferSize = bytesread; sl@0: } sl@0: sl@0: totalbytesread += bytesread; sl@0: foundIndex += 1; sl@0: found = MP4TRUE; sl@0: } sl@0: else sl@0: { sl@0: bytesread = readUnknown(handle); sl@0: if (bytesread < 0) sl@0: return MP4_ERROR; sl@0: totalbytesread += bytesread; sl@0: foundIndex += 1; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: bytesread = readUnknown(handle); sl@0: if (bytesread < 0) sl@0: return MP4_ERROR; sl@0: totalbytesread += bytesread; sl@0: } sl@0: } sl@0: } sl@0: sl@0: if ( ( atomIndex > foundIndex ) || !found ) sl@0: { sl@0: retError = MP4_UDTA_NOT_FOUND; sl@0: } sl@0: sl@0: // fill how many wanted type atom there is in asked UDTA. sl@0: if ( found ) sl@0: { sl@0: atomIndex = foundIndex - 1; sl@0: } sl@0: else sl@0: { sl@0: atomIndex = 0; sl@0: } sl@0: sl@0: // fill udtaLocation sl@0: udtaLocation = MP4_UDTA_NONE; sl@0: sl@0: if ( handle->moov->udta ) sl@0: { sl@0: udtaLocation |= MP4_UDTA_MOOV; sl@0: } sl@0: if ( handle->moov->trakVideo ) sl@0: { sl@0: if ( handle->moov->trakVideo->udta ) sl@0: { sl@0: udtaLocation |= MP4_UDTA_VIDEOTRAK; sl@0: } sl@0: } sl@0: if ( handle->moov->trakAudio ) sl@0: { sl@0: if ( handle->moov->trakAudio->udta ) sl@0: { sl@0: udtaLocation |= MP4_UDTA_AUDIOTRAK; sl@0: } sl@0: } sl@0: sl@0: return retError; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseNextVideoFrameDependencies(MP4Handle apihandle, mp4_u8* aDependsOn, mp4_u8* aIsDependentOn, mp4_u8* aHasRedundancy) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: mp4_u32 type = 0; sl@0: sl@0: if (!handle) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if(!aDependsOn || !aIsDependentOn || !aHasRedundancy) sl@0: { sl@0: return MP4_NO_OUTPUT_BUFFER; sl@0: } sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (determineVideoType(handle, &type) < 0) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: if( !isAvcVideo(type) ) sl@0: { sl@0: *aDependsOn = 0; // Unknown sl@0: *aIsDependentOn = 0; // Unknown sl@0: *aHasRedundancy = 0; // Unknown sl@0: return MP4_OK; sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo->mdia) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo->mdia->minf) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->sdtp) sl@0: { sl@0: *aDependsOn = 0; // Unknown sl@0: *aIsDependentOn = 0; // Unknown sl@0: *aHasRedundancy = 0; // Unknown sl@0: return MP4_OK; sl@0: } sl@0: if (!handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (handle->videoSampleNum <= 0) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if(handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep[handle->videoSampleNum - 1].sDependsOn > 2 || sl@0: handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep[handle->videoSampleNum - 1].sIsDependentOn > 2 || sl@0: handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep[handle->videoSampleNum - 1].sHasRedundancy > 2) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: *aDependsOn = handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep[handle->videoSampleNum - 1].sDependsOn; sl@0: *aIsDependentOn = handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep[handle->videoSampleNum - 1].sIsDependentOn; sl@0: *aHasRedundancy = handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep[handle->videoSampleNum - 1].sHasRedundancy; sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseReadAudioFramesAsync(MP4Handle apihandle, M3GPMP4LibAsyncObserver* aObserver, mp4_u8 *buffer, mp4_u32* buffersize) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle->file) sl@0: { sl@0: // async operation is only supported for files. sl@0: return MP4_FILE_ERROR; sl@0: } sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: handle->asyncObserver = aObserver; sl@0: sl@0: /* Is audio available? */ sl@0: if (!((handle->type & MP4_TYPE_MPEG4_AUDIO) || sl@0: (handle->type & MP4_TYPE_AMR_NB) || sl@0: (handle->type & MP4_TYPE_AMR_WB) || sl@0: (handle->type & MP4_TYPE_QCELP_13K))) sl@0: return MP4_ERROR; sl@0: sl@0: /* Are there samples left? */ sl@0: if (handle->audioLast) sl@0: return MP4_NO_FRAME; sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakAudio) sl@0: return MP4_ERROR; sl@0: sl@0: switch (fetchAudioSampleAsync(handle, handle->moov->trakAudio, buffer, buffersize)) sl@0: { sl@0: case -1: sl@0: return MP4_ERROR; sl@0: case -2: sl@0: return MP4_BUFFER_TOO_SMALL; sl@0: case -4: sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: case MP4_OUT_OF_MEMORY: sl@0: return MP4_OUT_OF_MEMORY; sl@0: default: sl@0: break; sl@0: } sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseReadVideoFrameAsync(MP4Handle apihandle, sl@0: M3GPMP4LibAsyncObserver* aObserver, sl@0: mp4_u8* buffer, sl@0: mp4_u32* buffersize) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle->file) sl@0: { sl@0: // async operation is only supported for files. sl@0: return MP4_FILE_ERROR; sl@0: } sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: sl@0: if ( handle->cafError != KErrNone ) sl@0: { sl@0: // if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: /* Is video available? */ sl@0: if (!((handle->type & MP4_TYPE_MPEG4_VIDEO) || sl@0: (handle->type & MP4_TYPE_H263_PROFILE_0) || sl@0: (handle->type & MP4_TYPE_H263_PROFILE_3) || sl@0: containsAvcVideo( handle->type ) )) sl@0: return MP4_ERROR; sl@0: sl@0: /* Are there samples left? */ sl@0: if (handle->videoLast) sl@0: return MP4_NO_FRAME; sl@0: sl@0: handle->asyncObserver = aObserver; sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: if (!handle->moov->trakVideo) sl@0: return MP4_ERROR; sl@0: sl@0: switch (fetchVideoFrameAsync(handle, handle->moov->trakVideo, buffer, buffersize )) sl@0: { sl@0: case -1: sl@0: return MP4_ERROR; sl@0: case -2: sl@0: return MP4_BUFFER_TOO_SMALL; sl@0: case -3: sl@0: return MP4_NOT_AVAILABLE; sl@0: case -4: sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: case MP4_OUT_OF_MEMORY: sl@0: return MP4_OUT_OF_MEMORY; sl@0: default: sl@0: break; sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: sl@0: extern EXPORT_C void MP4CancelReadFrame(MP4Handle ahandle) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)ahandle; sl@0: sl@0: if (handle->asyncReader) sl@0: { sl@0: handle->asyncReader->Cancel(); sl@0: } sl@0: } sl@0: sl@0: extern EXPORT_C MP4Err MP4ParseGetID32Location(MP4Handle apihandle, mp4_u32& location) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)apihandle; sl@0: sl@0: if (!handle) sl@0: { sl@0: return MP4_ERROR; sl@0: } sl@0: sl@0: if (!handle->metaDataComplete) sl@0: { sl@0: switch (metaDataAvailable(handle)) sl@0: { sl@0: case 0: sl@0: return MP4_NOT_AVAILABLE; sl@0: case 1: sl@0: handle->cafError = KErrNone; sl@0: if (readMetaData(handle) < 0) sl@0: { sl@0: // Reading of meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: freeMOOV(handle->moov); sl@0: handle->moov = NULL; sl@0: if (handle->cafError != KErrNone) sl@0: {// if CAF/DRM caused the error return it instead of generic errorcode. sl@0: return handle->cafError; sl@0: } sl@0: else sl@0: { sl@0: return MP4_INVALID_INPUT_STREAM; sl@0: } sl@0: } sl@0: handle->metaDataComplete = MP4TRUE; sl@0: break; sl@0: sl@0: case -2: sl@0: // Reading of FTYP meta data failed, so free up any allocated memory sl@0: freeFTYP(handle->ftyp); sl@0: handle->ftyp = NULL; sl@0: return MP4_ERROR; sl@0: sl@0: case -1: sl@0: default: sl@0: return MP4_ERROR; sl@0: } sl@0: } sl@0: sl@0: if (!handle->moov) sl@0: return MP4_ERROR; sl@0: sl@0: metaAtom* meta = handle->moov->meta; sl@0: if (!meta) sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: if (!meta->atomhdr) sl@0: return MP4_NOT_AVAILABLE; sl@0: sl@0: if(meta->ID32) sl@0: { sl@0: location = meta->ID32->atomcontentloc; sl@0: } sl@0: else sl@0: { sl@0: return MP4_NOT_AVAILABLE; sl@0: } sl@0: sl@0: return MP4_OK; sl@0: } sl@0: // End of File