/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** ****************************************************************************** * @file M4VSS3GPP_Edit.c * @brief Video Studio Service 3GPP edit API implementation. * @note ****************************************************************************** */ /****************/ /*** Includes ***/ /****************/ #include "NXPSW_CompilerSwitches.h" /** * Our headers */ #include "M4VSS3GPP_API.h" #include "M4VSS3GPP_InternalTypes.h" #include "M4VSS3GPP_InternalFunctions.h" #include "M4VSS3GPP_InternalConfig.h" #include "M4VSS3GPP_ErrorCodes.h" /** * OSAL headers */ #include "M4OSA_Memory.h" /**< OSAL memory management */ #include "M4OSA_Debug.h" /**< OSAL debug management */ #include "M4OSA_CharStar.h" /**< OSAL string management */ #ifdef WIN32 #include "string.h" /**< for strcpy (Don't want to get dependencies with M4OSA_String...) */ #endif /* WIN32 */ #ifdef M4VSS_ENABLE_EXTERNAL_DECODERS #include "M4VD_EXTERNAL_Interface.h" #endif /************************************************************************/ /* Static local functions */ /************************************************************************/ static M4OSA_ERR M4VSS3GPP_intClipSettingsSanityCheck( M4VSS3GPP_ClipSettings *pClip ); static M4OSA_ERR M4VSS3GPP_intTransitionSettingsSanityCheck( M4VSS3GPP_TransitionSettings *pTransition ); static M4OSA_Void M4VSS3GPP_intFreeSettingsList( M4VSS3GPP_InternalEditContext *pC ); static M4OSA_ERR M4VSS3GPP_intCreateMP3OutputFile( M4VSS3GPP_InternalEditContext *pC, M4OSA_Void *pOutputFile ); static M4OSA_ERR M4VSS3GPP_intSwitchToNextClip( M4VSS3GPP_InternalEditContext *pC ); static M4OSA_ERR M4VSS3GPP_intComputeOutputVideoAndAudioDsi( M4VSS3GPP_InternalEditContext *pC, M4OSA_UInt8 uiMasterClip ); static M4OSA_Void M4VSS3GPP_intComputeOutputAverageVideoBitrate( M4VSS3GPP_InternalEditContext *pC ); /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_GetVersion() * @brief Get the VSS 3GPP version. * @note Can be called anytime. Do not need any context. * @param pVersionInfo (OUT) Pointer to a version info structure * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pVersionInfo is M4OSA_NULL (If Debug Level >= 2) ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_GetVersion( M4_VersionInfo *pVersionInfo ) { M4OSA_TRACE3_1("M4VSS3GPP_GetVersion called with pVersionInfo=0x%x", pVersionInfo); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pVersionInfo), M4ERR_PARAMETER, "M4VSS3GPP_GetVersion: pVersionInfo is M4OSA_NULL"); pVersionInfo->m_major = M4VSS_VERSION_MAJOR; pVersionInfo->m_minor = M4VSS_VERSION_MINOR; pVersionInfo->m_revision = M4VSS_VERSION_REVISION; return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_editInit() * @brief Initializes the VSS 3GPP edit operation (allocates an execution context). * @note * @param pContext (OUT) Pointer on the VSS 3GPP edit context to allocate * @param pFileReadPtrFct (IN) Pointer to OSAL file reader functions * @param pFileWritePtrFct (IN) Pointer to OSAL file writer functions * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL * @return M4ERR_ALLOC: There is no more available memory ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_editInit( M4VSS3GPP_EditContext *pContext, M4OSA_FileReadPointer *pFileReadPtrFct, M4OSA_FileWriterPointer *pFileWritePtrFct ) { M4VSS3GPP_InternalEditContext *pC; M4OSA_ERR err; M4OSA_UInt32 i; M4OSA_TRACE3_3( "M4VSS3GPP_editInit called with pContext=0x%x, \ pFileReadPtrFct=0x%x, pFileWritePtrFct=0x%x", pContext, pFileReadPtrFct, pFileWritePtrFct); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4VSS3GPP_editInit: pContext is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pFileReadPtrFct), M4ERR_PARAMETER, "M4VSS3GPP_editInit: pFileReadPtrFct is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pFileWritePtrFct), M4ERR_PARAMETER, "M4VSS3GPP_editInit: pFileWritePtrFct is M4OSA_NULL"); /** * Allocate the VSS context and return it to the user */ pC = (M4VSS3GPP_InternalEditContext *)M4OSA_32bitAlignedMalloc(sizeof(M4VSS3GPP_InternalEditContext), M4VSS3GPP, (M4OSA_Char *)"M4VSS3GPP_InternalContext"); *pContext = pC; /* Inialization of context Variables */ memset((void *)pC, 0,sizeof(M4VSS3GPP_InternalEditContext)); if( M4OSA_NULL == pC ) { M4OSA_TRACE1_0( "M4VSS3GPP_editInit(): unable to allocate M4VSS3GPP_InternalContext,\ returning M4ERR_ALLOC"); return M4ERR_ALLOC; } /* Init the context. */ pC->uiClipNumber = 0; pC->pClipList = M4OSA_NULL; pC->pTransitionList = M4OSA_NULL; pC->pEffectsList = M4OSA_NULL; pC->pActiveEffectsList = M4OSA_NULL; pC->pActiveEffectsList1 = M4OSA_NULL; pC->bClip1ActiveFramingEffect = M4OSA_FALSE; pC->bClip2ActiveFramingEffect = M4OSA_FALSE; pC->uiCurrentClip = 0; pC->pC1 = M4OSA_NULL; pC->pC2 = M4OSA_NULL; pC->yuv1[0].pac_data = pC->yuv1[1].pac_data = pC-> yuv1[2].pac_data = M4OSA_NULL; pC->yuv2[0].pac_data = pC->yuv2[1].pac_data = pC-> yuv2[2].pac_data = M4OSA_NULL; pC->yuv3[0].pac_data = pC->yuv3[1].pac_data = pC-> yuv3[2].pac_data = M4OSA_NULL; pC->yuv4[0].pac_data = pC->yuv4[1].pac_data = pC-> yuv4[2].pac_data = M4OSA_NULL; pC->bClip1AtBeginCut = M4OSA_FALSE; pC->iClip1ActiveEffect = 0; pC->iClip2ActiveEffect = 0; pC->bTransitionEffect = M4OSA_FALSE; pC->bSupportSilence = M4OSA_FALSE; /** * Init PC->ewc members */ // Decorrelate input and output encoding timestamp to handle encoder prefetch pC->ewc.dInputVidCts = 0.0; pC->ewc.dOutputVidCts = 0.0; pC->ewc.dATo = 0.0; pC->ewc.iOutputDuration = 0; pC->ewc.VideoStreamType = M4SYS_kVideoUnknown; pC->ewc.uiVideoBitrate = 0; pC->ewc.uiVideoWidth = 0; pC->ewc.uiVideoHeight = 0; pC->ewc.uiVideoTimeScale = 0; pC->ewc.bVideoDataPartitioning = M4OSA_FALSE; pC->ewc.pVideoOutputDsi = M4OSA_NULL; pC->ewc.uiVideoOutputDsiSize = 0; pC->ewc.AudioStreamType = M4SYS_kAudioUnknown; pC->ewc.uiNbChannels = 1; pC->ewc.uiAudioBitrate = 0; pC->ewc.uiSamplingFrequency = 0; pC->ewc.pAudioOutputDsi = M4OSA_NULL; pC->ewc.uiAudioOutputDsiSize = 0; pC->ewc.pAudioEncCtxt = M4OSA_NULL; pC->ewc.pAudioEncDSI.infoSize = 0; pC->ewc.pAudioEncDSI.pInfo = M4OSA_NULL; pC->ewc.uiSilencePcmSize = 0; pC->ewc.pSilenceFrameData = M4OSA_NULL; pC->ewc.uiSilenceFrameSize = 0; pC->ewc.iSilenceFrameDuration = 0; pC->ewc.scale_audio = 0.0; pC->ewc.pEncContext = M4OSA_NULL; pC->ewc.pDummyAuBuffer = M4OSA_NULL; pC->ewc.iMpeg4GovOffset = 0; pC->ewc.VppError = 0; pC->ewc.encoderState = M4VSS3GPP_kNoEncoder; pC->ewc.p3gpWriterContext = M4OSA_NULL; pC->ewc.uiVideoMaxAuSize = 0; pC->ewc.uiAudioMaxAuSize = 0; /** * Keep the OSAL file functions pointer set in our context */ pC->pOsaFileReadPtr = pFileReadPtrFct; pC->pOsaFileWritPtr = pFileWritePtrFct; /* * Reset pointers for media and codecs interfaces */ err = M4VSS3GPP_clearInterfaceTables(&pC->ShellAPI); M4ERR_CHECK_RETURN(err); /* * Call the media and codecs subscription module */ err = M4VSS3GPP_subscribeMediaAndCodec(&pC->ShellAPI); M4ERR_CHECK_RETURN(err); /** * Update main state automaton */ pC->State = M4VSS3GPP_kEditState_CREATED; pC->Vstate = M4VSS3GPP_kEditVideoState_READ_WRITE; pC->Astate = M4VSS3GPP_kEditAudioState_READ_WRITE; /* The flag is set to false at the beginning of every clip */ pC->m_bClipExternalHasStarted = M4OSA_FALSE; pC->bIsMMS = M4OSA_FALSE; pC->iInOutTimeOffset = 0; pC->bEncodeTillEoF = M4OSA_FALSE; pC->nbActiveEffects = 0; pC->nbActiveEffects1 = 0; pC->bIssecondClip = M4OSA_FALSE; pC->m_air_context = M4OSA_NULL; /** * Return with no error */ M4OSA_TRACE3_0("M4VSS3GPP_editInit(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_editCreateClipSettings() * @brief Allows filling a clip settings structure with default values * * @note WARNING: pClipSettings->Effects[ ] will be allocated in this function. * pClipSettings->pFile will be allocated in this function. * * @param pClipSettings (IN) Pointer to a valid M4VSS3GPP_ClipSettings structure * @param pFile (IN) Clip file name * @param filePathSize (IN) Clip path size (needed for UTF 16 conversion) * @param nbEffects (IN) Nb of effect settings to allocate * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pClipSettings is M4OSA_NULL (debug only) ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_editCreateClipSettings( M4VSS3GPP_ClipSettings *pClipSettings, M4OSA_Void *pFile, M4OSA_UInt32 filePathSize, M4OSA_UInt8 nbEffects ) { M4OSA_UInt8 uiFx; M4OSA_TRACE3_1( "M4VSS3GPP_editCreateClipSettings called with pClipSettings=0x%p", pClipSettings); /** * Check input parameter */ M4OSA_DEBUG_IF2((M4OSA_NULL == pClipSettings), M4ERR_PARAMETER, "M4VSS3GPP_editCreateClipSettings: pClipSettings is NULL"); /** * Set the clip settings to default */ pClipSettings->pFile = M4OSA_NULL; /**< no file */ pClipSettings->FileType = M4VIDEOEDITING_kFileType_Unsupported; /**< undefined */ if( M4OSA_NULL != pFile ) { //pClipSettings->pFile = (M4OSA_Char*) M4OSA_32bitAlignedMalloc(strlen(pFile)+1, M4VSS3GPP, // "pClipSettings->pFile"); /*FB: add clip path size because of utf 16 conversion*/ pClipSettings->pFile = (M4OSA_Void *)M4OSA_32bitAlignedMalloc(filePathSize + 1, M4VSS3GPP, (M4OSA_Char *)"pClipSettings->pFile"); if( M4OSA_NULL == pClipSettings->pFile ) { M4OSA_TRACE1_0( "M4VSS3GPP_editCreateClipSettings : ERROR allocating filename"); return M4ERR_ALLOC; } //memcpy(pClipSettings->pFile, pFile, strlen(pFile)+1); /*FB: add clip path size because of utf 16 conversion*/ memcpy((void *)pClipSettings->pFile, (void *)pFile, filePathSize + 1); } /*FB: add file path size to support UTF16 conversion*/ pClipSettings->filePathSize = filePathSize + 1; /**/ pClipSettings->ClipProperties.bAnalysed = M4OSA_FALSE; pClipSettings->ClipProperties.FileType = 0; pClipSettings->ClipProperties.Version[0] = 0; pClipSettings->ClipProperties.Version[1] = 0; pClipSettings->ClipProperties.Version[2] = 0; pClipSettings->ClipProperties.uiClipDuration = 0; pClipSettings->uiBeginCutTime = 0; /**< no begin cut */ pClipSettings->uiEndCutTime = 0; /**< no end cut */ pClipSettings->ClipProperties.bSetImageData = M4OSA_FALSE; /** * Reset video characteristics */ pClipSettings->ClipProperties.VideoStreamType = M4VIDEOEDITING_kNoneVideo; pClipSettings->ClipProperties.uiClipVideoDuration = 0; pClipSettings->ClipProperties.uiVideoBitrate = 0; pClipSettings->ClipProperties.uiVideoMaxAuSize = 0; pClipSettings->ClipProperties.uiVideoWidth = 0; pClipSettings->ClipProperties.uiVideoHeight = 0; pClipSettings->ClipProperties.uiVideoTimeScale = 0; pClipSettings->ClipProperties.fAverageFrameRate = 0.0; pClipSettings->ClipProperties.uiVideoProfile = M4VIDEOEDITING_VIDEO_UNKNOWN_PROFILE; pClipSettings->ClipProperties.uiVideoLevel = M4VIDEOEDITING_VIDEO_UNKNOWN_LEVEL; pClipSettings->ClipProperties.bMPEG4dataPartition = M4OSA_FALSE; pClipSettings->ClipProperties.bMPEG4rvlc = M4OSA_FALSE; pClipSettings->ClipProperties.bMPEG4resynchMarker = M4OSA_FALSE; /** * Reset audio characteristics */ pClipSettings->ClipProperties.AudioStreamType = M4VIDEOEDITING_kNoneAudio; pClipSettings->ClipProperties.uiClipAudioDuration = 0; pClipSettings->ClipProperties.uiAudioBitrate = 0; pClipSettings->ClipProperties.uiAudioMaxAuSize = 0; pClipSettings->ClipProperties.uiNbChannels = 0; pClipSettings->ClipProperties.uiSamplingFrequency = 0; pClipSettings->ClipProperties.uiExtendedSamplingFrequency = 0; pClipSettings->ClipProperties.uiDecodedPcmSize = 0; /** * Return with no error */ M4OSA_TRACE3_0("M4VSS3GPP_editSetDefaultSettings(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_editDuplicateClipSettings() * @brief Duplicates a clip settings structure, performing allocations if required * * @param pClipSettingsDest (IN) Pointer to a valid M4VSS3GPP_ClipSettings structure * @param pClipSettingsOrig (IN) Pointer to a valid M4VSS3GPP_ClipSettings structure * @param bCopyEffects (IN) Flag to know if we have to duplicate effects * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pClipSettings is M4OSA_NULL (debug only) ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_editDuplicateClipSettings( M4VSS3GPP_ClipSettings *pClipSettingsDest, M4VSS3GPP_ClipSettings *pClipSettingsOrig, M4OSA_Bool bCopyEffects ) { M4OSA_UInt8 uiFx; M4OSA_TRACE3_2( "M4VSS3GPP_editDuplicateClipSettings called with dest=0x%p src=0x%p", pClipSettingsDest, pClipSettingsOrig); /* Check input parameter */ M4OSA_DEBUG_IF2((M4OSA_NULL == pClipSettingsDest), M4ERR_PARAMETER, "M4VSS3GPP_editDuplicateClipSettings: pClipSettingsDest is NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pClipSettingsOrig), M4ERR_PARAMETER, "M4VSS3GPP_editDuplicateClipSettings: pClipSettingsOrig is NULL"); /* Copy plain structure */ memcpy((void *)pClipSettingsDest, (void *)pClipSettingsOrig, sizeof(M4VSS3GPP_ClipSettings)); /* Duplicate filename */ if( M4OSA_NULL != pClipSettingsOrig->pFile ) { //pClipSettingsDest->pFile = // (M4OSA_Char*) M4OSA_32bitAlignedMalloc(strlen(pClipSettingsOrig->pFile)+1, M4VSS3GPP, // "pClipSettingsDest->pFile"); /*FB: clip path size is needed for utf 16 conversion*/ /*FB 2008/10/16: bad allocation size which raises a crash*/ pClipSettingsDest->pFile = (M4OSA_Char *)M4OSA_32bitAlignedMalloc(pClipSettingsOrig->filePathSize + 1, M4VSS3GPP, (M4OSA_Char *)"pClipSettingsDest->pFile"); if( M4OSA_NULL == pClipSettingsDest->pFile ) { M4OSA_TRACE1_0( "M4VSS3GPP_editDuplicateClipSettings : ERROR allocating filename"); return M4ERR_ALLOC; } /*FB: clip path size is needed for utf 16 conversion*/ //memcpy(pClipSettingsDest->pFile, pClipSettingsOrig->pFile, // strlen(pClipSettingsOrig->pFile)+1); /*FB 2008/10/16: bad allocation size which raises a crash*/ memcpy((void *)pClipSettingsDest->pFile, (void *)pClipSettingsOrig->pFile, pClipSettingsOrig->filePathSize/*+1*/); ( (M4OSA_Char *)pClipSettingsDest->pFile)[pClipSettingsOrig->filePathSize] = '\0'; } /* Duplicate effects */ /* Return with no error */ M4OSA_TRACE3_0( "M4VSS3GPP_editDuplicateClipSettings(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_editFreeClipSettings() * @brief Free the pointers allocated in the ClipSetting structure (pFile, Effects). * * @param pClipSettings (IN) Pointer to a valid M4VSS3GPP_ClipSettings structure * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pClipSettings is M4OSA_NULL (debug only) ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_editFreeClipSettings( M4VSS3GPP_ClipSettings *pClipSettings ) { /** * Check input parameter */ M4OSA_DEBUG_IF2((M4OSA_NULL == pClipSettings), M4ERR_PARAMETER, "M4VSS3GPP_editFreeClipSettings: pClipSettings is NULL"); /* free filename */ if( M4OSA_NULL != pClipSettings->pFile ) { free(pClipSettings->pFile); pClipSettings->pFile = M4OSA_NULL; } /* free effects settings */ /* if(M4OSA_NULL != pClipSettings->Effects) { free(pClipSettings->Effects); pClipSettings->Effects = M4OSA_NULL; pClipSettings->nbEffects = 0; } RC */ return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_editOpen() * @brief Set the VSS input and output files. * @note It opens the input file, but the output file may not be created yet. * @param pContext (IN) VSS edit context * @param pSettings (IN) Edit settings * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL (debug only) * @return M4ERR_STATE: VSS is not in an appropriate state for this function to be called * @return M4ERR_ALLOC: There is no more available memory ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_editOpen( M4VSS3GPP_EditContext pContext, M4VSS3GPP_EditSettings *pSettings ) { M4VSS3GPP_InternalEditContext *pC = (M4VSS3GPP_InternalEditContext *)pContext; M4OSA_ERR err; M4OSA_Int32 i; M4VIDEOEDITING_FileType outputFileType = M4VIDEOEDITING_kFileType_Unsupported; /**< 3GPP or MP3 (we don't do AMR output) */ M4OSA_UInt32 uiC1duration, uiC2duration; M4OSA_TRACE3_2( "M4VSS3GPP_editOpen called with pContext=0x%x, pSettings=0x%x", pContext, pSettings); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4VSS3GPP_editOpen: pContext is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pSettings), M4ERR_PARAMETER, "M4VSS3GPP_editOpen: pSettings is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pSettings->pClipList), M4ERR_PARAMETER, "M4VSS3GPP_editOpen: pSettings->pClipList is M4OSA_NULL"); M4OSA_DEBUG_IF2(( pSettings->uiClipNumber > 1) && (M4OSA_NULL == pSettings->pTransitionList), M4ERR_PARAMETER, "M4VSS3GPP_editOpen: pSettings->pTransitionList is M4OSA_NULL"); /** * Check state automaton */ if( ( pC->State != M4VSS3GPP_kEditState_CREATED) && (pC->State != M4VSS3GPP_kEditState_CLOSED) ) { M4OSA_TRACE1_1( "M4VSS3GPP_editOpen: State error (0x%x)! Returning M4ERR_STATE", pC->State); return M4ERR_STATE; } /** * Free any previously allocated internal settings list */ M4VSS3GPP_intFreeSettingsList(pC); /** * Copy the user settings in our context */ pC->uiClipNumber = pSettings->uiClipNumber; /** * Copy the clip list */ pC->pClipList = (M4VSS3GPP_ClipSettings *)M4OSA_32bitAlignedMalloc(sizeof(M4VSS3GPP_ClipSettings) * pC->uiClipNumber, M4VSS3GPP, (M4OSA_Char *)"pC->pClipList"); if( M4OSA_NULL == pC->pClipList ) { M4OSA_TRACE1_0( "M4VSS3GPP_editOpen: unable to allocate pC->Settings.pClipList,\ returning M4ERR_ALLOC"); return M4ERR_ALLOC; } for ( i = 0; i < pSettings->uiClipNumber; i++ ) { M4VSS3GPP_editDuplicateClipSettings(&(pC->pClipList[i]), pSettings->pClipList[i], M4OSA_TRUE); } /** * Copy effects list RC */ /*FB bug fix 19.03.2008 if the number of effects is 0 -> crash*/ if( pSettings->nbEffects > 0 ) { pC->nbEffects = pSettings->nbEffects; pC->pEffectsList = (M4VSS3GPP_EffectSettings *)M4OSA_32bitAlignedMalloc(sizeof(M4VSS3GPP_EffectSettings) * pC->nbEffects, M4VSS3GPP, (M4OSA_Char *)"pC->pEffectsList"); if( M4OSA_NULL == pC->pEffectsList ) { M4OSA_TRACE1_0( "M4VSS3GPP_editOpen: unable to allocate pC->pEffectsList, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } for ( i = 0; i < pC->nbEffects; i++ ) { memcpy((void *) &(pC->pEffectsList[i]), (void *) &(pSettings->Effects[i]), sizeof(M4VSS3GPP_EffectSettings)); } /** * Allocate active effects list RC */ pC->pActiveEffectsList = (M4OSA_UInt8 *)M4OSA_32bitAlignedMalloc(sizeof(M4OSA_UInt8) * pC->nbEffects, M4VSS3GPP, (M4OSA_Char *)"pC->pActiveEffectsList"); if( M4OSA_NULL == pC->pActiveEffectsList ) { M4OSA_TRACE1_0( "M4VSS3GPP_editOpen: unable to allocate pC->pActiveEffectsList,\ returning M4ERR_ALLOC"); return M4ERR_ALLOC; } /** * Allocate active effects list */ pC->pActiveEffectsList1 = (M4OSA_UInt8 *)M4OSA_32bitAlignedMalloc(sizeof(M4OSA_UInt8) * pC->nbEffects, M4VSS3GPP, (M4OSA_Char *)"pC->pActiveEffectsList"); if (M4OSA_NULL == pC->pActiveEffectsList1) { M4OSA_TRACE1_0("M4VSS3GPP_editOpen: unable to allocate pC->pActiveEffectsList, \ returning M4ERR_ALLOC"); return M4ERR_ALLOC; } } else { pC->nbEffects = 0; pC->nbActiveEffects = 0; pC->nbActiveEffects1 = 0; pC->pEffectsList = M4OSA_NULL; pC->pActiveEffectsList = M4OSA_NULL; pC->pActiveEffectsList1 = M4OSA_NULL; pC->bClip1ActiveFramingEffect = M4OSA_FALSE; pC->bClip2ActiveFramingEffect = M4OSA_FALSE; } /** * Test the clip analysis data, if it is not provided, analyse the clips by ourselves. */ for ( i = 0; i < pC->uiClipNumber; i++ ) { if( M4OSA_FALSE == pC->pClipList[i].ClipProperties.bAnalysed ) { /**< Analysis not provided by the integrator */ err = M4VSS3GPP_editAnalyseClip(pC->pClipList[i].pFile, pC->pClipList[i].FileType, &pC->pClipList[i].ClipProperties, pC->pOsaFileReadPtr); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editOpen: M4VSS3GPP_editAnalyseClip returns 0x%x!", err); return err; } } } /** * Check clip compatibility */ for ( i = 0; i < pC->uiClipNumber; i++ ) { if (pC->pClipList[i].FileType !=M4VIDEOEDITING_kFileType_ARGB8888) { /** * Check all the clips are compatible with VSS 3GPP */ err = M4VSS3GPP_intCheckClipCompatibleWithVssEditing( &pC->pClipList[i].ClipProperties); if( M4NO_ERROR != err ) { M4OSA_TRACE1_2( "M4VSS3GPP_editOpen:\ M4VSS3GPP_intCheckClipCompatibleWithVssEditing(%d) returns 0x%x!", i, err); return err; } } /** * Check the master clip versus all the other ones. (including master clip with itself, else variables for master clip are not properly setted) */ if(pC->pClipList[i].FileType != M4VIDEOEDITING_kFileType_ARGB8888) { err = M4VSS3GPP_editCheckClipCompatibility( &pC->pClipList[pSettings->uiMasterClip].ClipProperties, &pC->pClipList[i].ClipProperties); /* in case of warning regarding audio incompatibility, editing continues */ if( M4OSA_ERR_IS_ERROR(err) ) { M4OSA_TRACE1_2( "M4VSS3GPP_editOpen: M4VSS3GPP_editCheckClipCompatibility \ (%d) returns 0x%x!", i, err); return err; } } else { pC->pClipList[i].ClipProperties.bAudioIsCompatibleWithMasterClip = M4OSA_FALSE; } } /* Search audio tracks that cannot be edited : * - delete all audio effects for the clip * - if master clip is editable let the transition (bad track will be replaced later with silence) * - if master clip is not editable switch to a dummy transition (only copy/paste) */ for ( i = 0; i < pC->uiClipNumber; i++ ) { if( M4OSA_FALSE == pC->pClipList[i].ClipProperties.bAudioIsEditable ) { M4OSA_UInt8 uiFx; for ( uiFx = 0; uiFx < pC->nbEffects; uiFx++ ) { pC->pEffectsList[uiFx].AudioEffectType = M4VSS3GPP_kAudioEffectType_None; } if( ( i < (pC->uiClipNumber - 1)) && (M4OSA_NULL != pSettings->pTransitionList[i]) && (M4OSA_FALSE == pC->pClipList[pSettings-> uiMasterClip].ClipProperties.bAudioIsEditable) ) { pSettings->pTransitionList[i]->AudioTransitionType = M4VSS3GPP_kAudioTransitionType_None; } } } /** * We add a transition of duration 0 at the end of the last clip. * It will suppress a whole bunch a test latter in the processing... */ pC->pTransitionList = (M4VSS3GPP_TransitionSettings *)M4OSA_32bitAlignedMalloc(sizeof(M4VSS3GPP_TransitionSettings) * (pC->uiClipNumber), M4VSS3GPP, (M4OSA_Char *)"pC->pTransitionList"); if( M4OSA_NULL == pC->pTransitionList ) { M4OSA_TRACE1_0( "M4VSS3GPP_editOpen: unable to allocate pC->Settings.pTransitionList,\ returning M4ERR_ALLOC"); return M4ERR_ALLOC; } /**< copy transition settings */ for ( i = 0; i < (pSettings->uiClipNumber - 1); i++ ) { memcpy((void *) &(pC->pTransitionList[i]), (void *)pSettings->pTransitionList[i], sizeof(M4VSS3GPP_TransitionSettings)); } /**< We fill the last "dummy" transition */ pC->pTransitionList[pC->uiClipNumber - 1].uiTransitionDuration = 0; pC->pTransitionList[pC->uiClipNumber - 1].VideoTransitionType = M4VSS3GPP_kVideoTransitionType_None; pC->pTransitionList[pC->uiClipNumber - 1].AudioTransitionType = M4VSS3GPP_kAudioTransitionType_None; /** * Avoid weird clip settings */ for ( i = 0; i < pSettings->uiClipNumber; i++ ) { if (pC->pClipList[i].FileType !=M4VIDEOEDITING_kFileType_ARGB8888) { err = M4VSS3GPP_intClipSettingsSanityCheck(&pC->pClipList[i]); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editOpen: M4VSS3GPP_intClipSettingsSanityCheck returns 0x%x!", err); return err; } } } for ( i = 0; i < (pSettings->uiClipNumber - 1); i++ ) { if (pC->pTransitionList[i].uiTransitionDuration != 0) { if (pC->pClipList[i].FileType == M4VIDEOEDITING_kFileType_ARGB8888) { pC->pClipList[i].uiBeginCutTime = 0; pC->pClipList[i].uiEndCutTime = pC->pTransitionList[i].uiTransitionDuration; } if (pC->pClipList[i+1].FileType == M4VIDEOEDITING_kFileType_ARGB8888) { pC->pClipList[i+1].uiBeginCutTime = 0; pC->pClipList[i+1].uiEndCutTime = pC->pTransitionList[i].uiTransitionDuration; } } else { if (pC->pClipList[i].FileType == M4VIDEOEDITING_kFileType_ARGB8888) { pC->pClipList[i].uiEndCutTime = pC->pClipList[i].uiEndCutTime - pC->pClipList[i].uiBeginCutTime; pC->pClipList[i].uiBeginCutTime = 0; } if (pC->pClipList[i+1].FileType == M4VIDEOEDITING_kFileType_ARGB8888) { pC->pClipList[i+1].uiEndCutTime = pC->pClipList[i+1].uiEndCutTime - pC->pClipList[i+1].uiBeginCutTime; pC->pClipList[i+1].uiBeginCutTime = 0; } } /** * Maximum transition duration between clip n and clip n+1 is the duration * of the shortest clip */ if( 0 == pC->pClipList[i].uiEndCutTime ) { uiC1duration = pC->pClipList[i].ClipProperties.uiClipVideoDuration; } else { /**< duration of clip n is the end cut time */ uiC1duration = pC->pClipList[i].uiEndCutTime; } /**< Substract begin cut */ uiC1duration -= pC->pClipList[i].uiBeginCutTime; /**< Check that the transition is shorter than clip n */ if( pC->pTransitionList[i].uiTransitionDuration > uiC1duration ) { pC->pTransitionList[i].uiTransitionDuration = uiC1duration - 1; } if( 0 == pC->pClipList[i + 1].uiEndCutTime ) { uiC2duration = pC->pClipList[i + 1].ClipProperties.uiClipVideoDuration; } else { /**< duration of clip n+1 is the end cut time */ uiC2duration = pC->pClipList[i + 1].uiEndCutTime; } /**< Substract begin cut */ uiC2duration -= pC->pClipList[i + 1].uiBeginCutTime; /**< Check that the transition is shorter than clip n+1 */ if( pC->pTransitionList[i].uiTransitionDuration > uiC2duration ) { pC->pTransitionList[i].uiTransitionDuration = uiC2duration - 1; } /** * Avoid weird transition settings */ err = M4VSS3GPP_intTransitionSettingsSanityCheck(&pC->pTransitionList[i]); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editOpen: M4VSS3GPP_intClipSettingsSanityCheck returns 0x%x!", err); return err; } /** * Check that two transitions are not overlapping (no overlapping possible for first clip) */ if( i > 0 ) { /** * There is a transition overlap if the sum of the duration of two consecutive transitions * is higher than the duration of the clip in-between. */ if( ( pC->pTransitionList[i - 1].uiTransitionDuration + pC->pTransitionList[i].uiTransitionDuration) >= uiC1duration ) { M4OSA_TRACE1_1( "M4VSS3GPP_editOpen: Overlapping transitions on clip %d,\ returning M4VSS3GPP_ERR_OVERLAPPING_TRANSITIONS", i); return M4VSS3GPP_ERR_OVERLAPPING_TRANSITIONS; } } } /** * Output clip duration */ for ( i = 0; i < pC->uiClipNumber; i++ ) { /** * Compute the sum of the clip duration */ if( 0 == pC->pClipList[i].uiEndCutTime ) { pC->ewc.iOutputDuration += pC-> pClipList[ i].ClipProperties. uiClipVideoDuration; /* Only video track duration is important to avoid deviation if audio track is longer */ } else { pC->ewc.iOutputDuration += pC->pClipList[i].uiEndCutTime; /**< Add end cut */ } pC->ewc.iOutputDuration -= pC->pClipList[i].uiBeginCutTime; /**< Remove begin cut */ /** * Remove the duration of the transition (it is counted twice) */ pC->ewc.iOutputDuration -= pC->pTransitionList[i].uiTransitionDuration; } /* Get video properties from output properties */ /* Get output width and height */ switch(pC->xVSS.outputVideoSize) { case M4VIDEOEDITING_kSQCIF: pC->ewc.uiVideoWidth = 128; pC->ewc.uiVideoHeight = 96; break; case M4VIDEOEDITING_kQQVGA: pC->ewc.uiVideoWidth = 160; pC->ewc.uiVideoHeight = 120; break; case M4VIDEOEDITING_kQCIF: pC->ewc.uiVideoWidth = 176; pC->ewc.uiVideoHeight = 144; break; case M4VIDEOEDITING_kQVGA: pC->ewc.uiVideoWidth = 320; pC->ewc.uiVideoHeight = 240; break; case M4VIDEOEDITING_kCIF: pC->ewc.uiVideoWidth = 352; pC->ewc.uiVideoHeight = 288; break; case M4VIDEOEDITING_kVGA: pC->ewc.uiVideoWidth = 640; pC->ewc.uiVideoHeight = 480; break; /* +PR LV5807 */ case M4VIDEOEDITING_kWVGA: pC->ewc.uiVideoWidth = 800; pC->ewc.uiVideoHeight = 480; break; case M4VIDEOEDITING_kNTSC: pC->ewc.uiVideoWidth = 720; pC->ewc.uiVideoHeight = 480; break; /* -PR LV5807 */ /* +CR Google */ case M4VIDEOEDITING_k640_360: pC->ewc.uiVideoWidth = 640; pC->ewc.uiVideoHeight = 360; break; case M4VIDEOEDITING_k854_480: pC->ewc.uiVideoWidth = M4ENCODER_854_480_Width; pC->ewc.uiVideoHeight = 480; break; case M4VIDEOEDITING_k1280_720: pC->ewc.uiVideoWidth = 1280; pC->ewc.uiVideoHeight = 720; break; case M4VIDEOEDITING_k1080_720: pC->ewc.uiVideoWidth = M4ENCODER_1080_720_Width; pC->ewc.uiVideoHeight = 720; break; case M4VIDEOEDITING_k960_720: pC->ewc.uiVideoWidth = 960; pC->ewc.uiVideoHeight = 720; break; case M4VIDEOEDITING_k1920_1080: pC->ewc.uiVideoWidth = 1920; pC->ewc.uiVideoHeight = 1088; // need to be multiples of 16 break; default: /* If output video size is not given, we take QCIF size */ M4OSA_TRACE1_0( "M4VSS3GPP_editOpen: no output video size given, default to QCIF!"); pC->ewc.uiVideoWidth = 176; pC->ewc.uiVideoHeight = 144; pC->xVSS.outputVideoSize = M4VIDEOEDITING_kQCIF; break; } pC->ewc.uiVideoTimeScale = 30; pC->ewc.bVideoDataPartitioning = 0; /* Set output video profile and level */ pC->ewc.outputVideoProfile = pC->xVSS.outputVideoProfile; pC->ewc.outputVideoLevel = pC->xVSS.outputVideoLevel; switch(pC->xVSS.outputVideoFormat) { case M4VIDEOEDITING_kH263: pC->ewc.VideoStreamType = M4SYS_kH263; break; case M4VIDEOEDITING_kMPEG4: pC->ewc.VideoStreamType = M4SYS_kMPEG_4; break; case M4VIDEOEDITING_kH264: pC->ewc.VideoStreamType = M4SYS_kH264; break; default: pC->ewc.VideoStreamType = M4SYS_kVideoUnknown; break; } /** * Copy the audio properties of the master clip to the output properties */ pC->ewc.uiNbChannels = pC->pClipList[pSettings->uiMasterClip].ClipProperties.uiNbChannels; pC->ewc.uiAudioBitrate = pC->pClipList[pSettings->uiMasterClip].ClipProperties.uiAudioBitrate; pC->ewc.uiSamplingFrequency = pC->pClipList[pSettings-> uiMasterClip].ClipProperties.uiSamplingFrequency; pC->ewc.uiSilencePcmSize = pC->pClipList[pSettings->uiMasterClip].ClipProperties.uiDecodedPcmSize; pC->ewc.scale_audio = pC->ewc.uiSamplingFrequency / 1000.0; switch( pC->pClipList[pSettings->uiMasterClip].ClipProperties.AudioStreamType ) { case M4VIDEOEDITING_kAMR_NB: pC->ewc.AudioStreamType = M4SYS_kAMR; pC->ewc.pSilenceFrameData = (M4OSA_UInt8 *)M4VSS3GPP_AMR_AU_SILENCE_FRAME_048; pC->ewc.uiSilenceFrameSize = M4VSS3GPP_AMR_AU_SILENCE_FRAME_048_SIZE; pC->ewc.iSilenceFrameDuration = M4VSS3GPP_AMR_AU_SILENCE_FRAME_048_DURATION; pC->bSupportSilence = M4OSA_TRUE; break; case M4VIDEOEDITING_kAAC: case M4VIDEOEDITING_kAACplus: case M4VIDEOEDITING_keAACplus: pC->ewc.AudioStreamType = M4SYS_kAAC; if( pC->ewc.uiNbChannels == 1 ) { pC->ewc.pSilenceFrameData = (M4OSA_UInt8 *)M4VSS3GPP_AAC_AU_SILENCE_MONO; pC->ewc.uiSilenceFrameSize = M4VSS3GPP_AAC_AU_SILENCE_MONO_SIZE; pC->bSupportSilence = M4OSA_TRUE; } else { pC->ewc.pSilenceFrameData = (M4OSA_UInt8 *)M4VSS3GPP_AAC_AU_SILENCE_STEREO; pC->ewc.uiSilenceFrameSize = M4VSS3GPP_AAC_AU_SILENCE_STEREO_SIZE; pC->bSupportSilence = M4OSA_TRUE; } pC->ewc.iSilenceFrameDuration = 1024; /* AAC is always 1024/Freq sample duration */ break; case M4VIDEOEDITING_kMP3: pC->ewc.AudioStreamType = M4SYS_kMP3; pC->ewc.pSilenceFrameData = M4OSA_NULL; pC->ewc.uiSilenceFrameSize = 0; pC->ewc.iSilenceFrameDuration = 0; /* Special case, mp3 core reader return a time in ms */ pC->ewc.scale_audio = 1.0; break; case M4VIDEOEDITING_kEVRC: pC->ewc.AudioStreamType = M4SYS_kEVRC; pC->ewc.pSilenceFrameData = M4OSA_NULL; pC->ewc.uiSilenceFrameSize = 0; pC->ewc.iSilenceFrameDuration = 160; /* EVRC frames are 20 ms at 8000 Hz (makes it easier to factorize amr and evrc code) */ break; default: pC->ewc.AudioStreamType = M4SYS_kAudioUnknown; break; } for (i=0; i<pC->uiClipNumber; i++) { if (pC->pClipList[i].bTranscodingRequired == M4OSA_FALSE) { /** If not transcoded in Analysis phase, check * if transcoding required now */ if ((pC->pClipList[i].ClipProperties.VideoStreamType != pC->xVSS.outputVideoFormat)|| (pC->pClipList[i].ClipProperties.uiVideoWidth != pC->ewc.uiVideoWidth) || (pC->pClipList[i].ClipProperties.uiVideoHeight != pC->ewc.uiVideoHeight) || (pC->pClipList[i].ClipProperties.VideoStreamType == M4VIDEOEDITING_kH264) || (pC->pClipList[i].ClipProperties.VideoStreamType == M4VIDEOEDITING_kMPEG4 && pC->pClipList[i].ClipProperties.uiVideoTimeScale != pC->ewc.uiVideoTimeScale)) { pC->pClipList[i].bTranscodingRequired = M4OSA_TRUE; } } else { /** If bTranscodingRequired is true, it means the clip has * been transcoded in Analysis phase. */ pC->pClipList[i].bTranscodingRequired = M4OSA_FALSE; } } /** * We produce a 3gpp file, unless it is mp3 */ if( M4VIDEOEDITING_kMP3 == pC-> pClipList[pSettings->uiMasterClip].ClipProperties.AudioStreamType ) outputFileType = M4VIDEOEDITING_kFileType_MP3; else outputFileType = M4VIDEOEDITING_kFileType_3GPP; /** * Beware, a null duration would lead to a divide by zero error (better safe than sorry...) */ if( 0 == pC->ewc.iOutputDuration ) { pC->ewc.iOutputDuration = 1; } /** * Open first clip */ pC->uiCurrentClip = 0; // Decorrelate input and output encoding timestamp to handle encoder prefetch pC->ewc.dInputVidCts = 0.0; pC->ewc.dOutputVidCts = 0.0; pC->ewc.dATo = 0.0; err = M4VSS3GPP_intSwitchToNextClip(pC); /* RC: to know when a file has been processed */ if( M4NO_ERROR != err && err != M4VSS3GPP_WAR_SWITCH_CLIP ) { M4OSA_TRACE1_1( "M4VSS3GPP_editOpen: M4VSS3GPP_intSwitchToNextClip() returns 0x%x!", err); return err; } /** * Do the video stuff in 3GPP Audio/Video case */ if( M4VIDEOEDITING_kFileType_3GPP == outputFileType ) { /** * Compute the Decoder Specific Info for the output video and audio streams */ err = M4VSS3GPP_intComputeOutputVideoAndAudioDsi(pC, pSettings->uiMasterClip); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editOpen: M4VSS3GPP_intComputeOutputVideoAndAudioDsi() returns 0x%x!", err); return err; } /** * Compute the time increment for the transition file */ switch( pSettings->videoFrameRate ) { case M4VIDEOEDITING_k5_FPS: pC->dOutputFrameDuration = 1000.0 / 5.0; break; case M4VIDEOEDITING_k7_5_FPS: pC->dOutputFrameDuration = 1000.0 / 7.5; break; case M4VIDEOEDITING_k10_FPS: pC->dOutputFrameDuration = 1000.0 / 10.0; break; case M4VIDEOEDITING_k12_5_FPS: pC->dOutputFrameDuration = 1000.0 / 12.5; break; case M4VIDEOEDITING_k15_FPS: pC->dOutputFrameDuration = 1000.0 / 15.0; break; case M4VIDEOEDITING_k20_FPS: pC->dOutputFrameDuration = 1000.0 / 20.0; break; case M4VIDEOEDITING_k25_FPS: pC->dOutputFrameDuration = 1000.0 / 25.0; break; case M4VIDEOEDITING_k30_FPS: pC->dOutputFrameDuration = 1000.0 / 30.0; break; default: M4OSA_TRACE1_1( "M4VSS3GPP_editOpen(): invalid videoFrameRate (0x%x),\ returning M4VSS3GPP_ERR_INVALID_VIDEO_ENCODING_FRAME_RATE", pSettings->videoFrameRate); return M4VSS3GPP_ERR_INVALID_VIDEO_ENCODING_FRAME_RATE; } if( M4SYS_kMPEG_4 == pC->ewc.VideoStreamType ) { M4OSA_UInt32 uiAlpha; /** * MPEG-4 case. * Time scale of the transition encoder must be the same than the * timescale of the input files. * So the frame duration must be compatible with this time scale, * but without beeing too short. * For that, we must compute alpha (integer) so that: * (alpha x 1000)/EncoderTimeScale > MinFrameDuration **/ uiAlpha = (M4OSA_UInt32)(( pC->dOutputFrameDuration * pC->ewc.uiVideoTimeScale) / 1000.0 + 0.5); if( uiAlpha > 0 ) { pC->dOutputFrameDuration = ( uiAlpha * 1000.0) / pC->ewc.uiVideoTimeScale; } } else if( M4SYS_kH263 == pC->ewc.VideoStreamType ) { switch( pSettings->videoFrameRate ) { case M4VIDEOEDITING_k12_5_FPS: case M4VIDEOEDITING_k20_FPS: case M4VIDEOEDITING_k25_FPS: M4OSA_TRACE1_0( "M4VSS3GPP_editOpen(): invalid videoFrameRate for H263,\ returning M4VSS3GPP_ERR_INVALID_VIDEO_ENCODING_FRAME_RATE"); return M4VSS3GPP_ERR_INVALID_VIDEO_ENCODING_FRAME_RATE; default: break; } } } /** * Create the MP3 output file */ if( M4VIDEOEDITING_kFileType_MP3 == outputFileType ) { M4READER_Buffer mp3tagBuffer; err = M4VSS3GPP_intCreateMP3OutputFile(pC, pSettings->pOutputFile); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editOpen: M4VSS3GPP_intCreateMP3OutputFile returns 0x%x", err); return err; } /* The ID3v2 tag could be at any place in the mp3 file */ /* The mp3 reader only checks few bytes in the beginning of stream to look for a ID3v2 tag */ /* It means that if the ID3v2 tag is not at the beginning of the file the reader do as there is no these metadata */ /* Retrieve the data of the ID3v2 Tag */ err = pC->pC1->ShellAPI.m_pReader->m_pFctGetOption( pC->pC1->pReaderContext, M4READER_kOptionID_Mp3Id3v2Tag, (M4OSA_DataOption) &mp3tagBuffer); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1("M4VSS3GPP_editOpen: M4MP3R_getOption returns 0x%x", err); return err; } /* Write the data of the ID3v2 Tag in the output file */ if( 0 != mp3tagBuffer.m_uiBufferSize ) { err = pC->pOsaFileWritPtr->writeData(pC->ewc.p3gpWriterContext, (M4OSA_MemAddr8)mp3tagBuffer.m_pData, mp3tagBuffer.m_uiBufferSize); /** * Free before the error checking anyway */ free(mp3tagBuffer.m_pData); /** * Error checking */ if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editOpen: WriteData(ID3v2Tag) returns 0x%x", err); return err; } mp3tagBuffer.m_uiBufferSize = 0; mp3tagBuffer.m_pData = M4OSA_NULL; } } /** * Create the 3GPP output file */ else if( M4VIDEOEDITING_kFileType_3GPP == outputFileType ) { pC->ewc.uiVideoBitrate = pSettings->xVSS.outputVideoBitrate; /** * 11/12/2008 CR3283 MMS use case in VideoArtist: Set max output file size if needed */ if( pC->bIsMMS == M4OSA_TRUE ) { err = M4VSS3GPP_intCreate3GPPOutputFile(&pC->ewc, &pC->ShellAPI, pC->pOsaFileWritPtr, pSettings->pOutputFile, pC->pOsaFileReadPtr, pSettings->pTemporaryFile, pSettings->xVSS.outputFileSize); } else { err = M4VSS3GPP_intCreate3GPPOutputFile(&pC->ewc, &pC->ShellAPI, pC->pOsaFileWritPtr, pSettings->pOutputFile, pC->pOsaFileReadPtr, pSettings->pTemporaryFile, 0); } if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editOpen: M4VSS3GPP_intCreate3GPPOutputFile returns 0x%x", err); return err; } } /** * Default error case */ else { M4OSA_TRACE1_1( "M4VSS3GPP_editOpen: invalid outputFileType = 0x%x,\ returning M4VSS3GPP_ERR_OUTPUT_FILE_TYPE_ERROR", outputFileType); return M4VSS3GPP_ERR_OUTPUT_FILE_TYPE_ERROR; /**< this is an internal error code unknown to the user */ } /** * Initialize state */ if( M4SYS_kMP3 == pC->ewc.AudioStreamType ) { /** * In the MP3 case we use a special audio state */ pC->State = M4VSS3GPP_kEditState_MP3_JUMP; } else { /** * We start with the video processing */ pC->State = M4VSS3GPP_kEditState_VIDEO; } /** * Initialize state. * The first clip is independant to the "virtual previous clips", * so it's like if we where in Read/Write mode before it. */ pC->Vstate = M4VSS3GPP_kEditVideoState_READ_WRITE; pC->Astate = M4VSS3GPP_kEditAudioState_READ_WRITE; /** * Return with no error */ M4OSA_TRACE3_0("M4VSS3GPP_editOpen(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_editStep() * @brief Perform one step of editing. * @note * @param pContext (IN) VSS 3GPP edit context * @param pProgress (OUT) Progress percentage (0 to 100) of the editing operation * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only) * @return M4ERR_STATE: VSS 3GPP is not in an appropriate state for this * function to be called * @return M4VSS3GPP_WAR_EDITING_DONE: Edition is done, user should now call * M4VSS3GPP_editClose() ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_editStep( M4VSS3GPP_EditContext pContext, M4OSA_UInt8 *pProgress ) { M4VSS3GPP_InternalEditContext *pC = (M4VSS3GPP_InternalEditContext *)pContext; M4OSA_UInt32 uiProgressAudio, uiProgressVideo, uiProgress; M4OSA_ERR err; M4OSA_TRACE3_1("M4VSS3GPP_editStep called with pContext=0x%x", pContext); /** * Check input parameter */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4VSS3GPP_editStep: pContext is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pProgress), M4ERR_PARAMETER, "M4VSS3GPP_editStep: pProgress is M4OSA_NULL"); /** * Check state automaton and select correct processing */ switch( pC->State ) { case M4VSS3GPP_kEditState_VIDEO: err = M4VSS3GPP_intEditStepVideo(pC); break; case M4VSS3GPP_kEditState_AUDIO: err = M4VSS3GPP_intEditStepAudio(pC); break; case M4VSS3GPP_kEditState_MP3: err = M4VSS3GPP_intEditStepMP3(pC); break; case M4VSS3GPP_kEditState_MP3_JUMP: err = M4VSS3GPP_intEditJumpMP3(pC); break; default: M4OSA_TRACE1_0( "M4VSS3GPP_editStep(): invalid internal state (0x%x), returning M4ERR_STATE"); return M4ERR_STATE; } /** * Compute progress. * We do the computing with 32bits precision because in some (very) extreme case, we may get * values higher than 256 (...) */ uiProgressAudio = ( (M4OSA_UInt32)(pC->ewc.dATo * 100)) / pC->ewc.iOutputDuration; // Decorrelate input and output encoding timestamp to handle encoder prefetch uiProgressVideo = ((M4OSA_UInt32)(pC->ewc.dInputVidCts * 100)) / pC->ewc.iOutputDuration; uiProgress = uiProgressAudio + uiProgressVideo; if( ( pC->ewc.AudioStreamType != M4SYS_kAudioUnknown) && (pC->ewc.VideoStreamType != M4SYS_kVideoUnknown) ) uiProgress /= 2; /** * Sanity check */ if( uiProgress > 100 ) { *pProgress = 100; } else { *pProgress = (M4OSA_UInt8)uiProgress; } /** * Return the error */ M4OSA_TRACE3_1("M4VSS3GPP_editStep(): returning 0x%x", err); return err; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_editClose() * @brief Finish the VSS edit operation. * @note The output 3GPP file is ready to be played after this call * @param pContext (IN) VSS edit context * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only) * @return M4ERR_STATE: VSS is not in an appropriate state for this function to be called ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_editClose( M4VSS3GPP_EditContext pContext ) { M4VSS3GPP_InternalEditContext *pC = (M4VSS3GPP_InternalEditContext *)pContext; M4OSA_ERR err; M4OSA_ERR returnedError = M4NO_ERROR; M4OSA_UInt32 lastCTS; M4OSA_TRACE3_1("M4VSS3GPP_editClose called with pContext=0x%x", pContext); /** * Check input parameter */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4VSS3GPP_editClose: pContext is M4OSA_NULL"); /** * Check state automaton. * In "theory", we should not authorize closing if we are in CREATED state. * But in practice, in case the opening failed, it may have been partially done. * In that case we have to free some opened ressources by calling Close. */ if( M4VSS3GPP_kEditState_CLOSED == pC->State ) { M4OSA_TRACE1_1( "M4VSS3GPP_editClose: Wrong state (0x%x), returning M4ERR_STATE", pC->State); return M4ERR_STATE; } /** * There may be an encoder to destroy */ err = M4VSS3GPP_intDestroyVideoEncoder(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editClose: M4VSS3GPP_editDestroyVideoEncoder() returns 0x%x!", err); /**< We do not return the error here because we still have stuff to free */ returnedError = err; } /** * Close the output file */ if( M4SYS_kMP3 == pC->ewc.AudioStreamType ) { /** * MP3 case */ if( M4OSA_NULL != pC->ewc.p3gpWriterContext ) { err = pC->pOsaFileWritPtr->closeWrite(pC->ewc.p3gpWriterContext); pC->ewc.p3gpWriterContext = M4OSA_NULL; } } else { /** * Close the output 3GPP clip, if it has been opened */ if( M4OSA_NULL != pC->ewc.p3gpWriterContext ) { /* Update last Video CTS */ lastCTS = pC->ewc.iOutputDuration; err = pC->ShellAPI.pWriterGlobalFcts->pFctSetOption( pC->ewc.p3gpWriterContext, (M4OSA_UInt32)M4WRITER_kMaxFileDuration, &lastCTS); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editClose: SetOption(M4WRITER_kMaxFileDuration) returns 0x%x", err); } err = pC->ShellAPI.pWriterGlobalFcts->pFctCloseWrite( pC->ewc.p3gpWriterContext); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editClose: pFctCloseWrite(OUT) returns 0x%x!", err); /**< We do not return the error here because we still have stuff to free */ if( M4NO_ERROR == returnedError ) /**< we return the first error that happened */ { returnedError = err; } } pC->ewc.p3gpWriterContext = M4OSA_NULL; } } /** * Free the output video DSI, if it has been created */ if( M4OSA_NULL != pC->ewc.pVideoOutputDsi ) { free(pC->ewc.pVideoOutputDsi); pC->ewc.pVideoOutputDsi = M4OSA_NULL; } /** * Free the output audio DSI, if it has been created */ if( M4OSA_NULL != pC->ewc.pAudioOutputDsi ) { free(pC->ewc.pAudioOutputDsi); pC->ewc.pAudioOutputDsi = M4OSA_NULL; } /** * Close clip1, if needed */ if( M4OSA_NULL != pC->pC1 ) { err = M4VSS3GPP_intClipCleanUp(pC->pC1); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editClose: M4VSS3GPP_intClipCleanUp(C1) returns 0x%x!", err); /**< We do not return the error here because we still have stuff to free */ if( M4NO_ERROR == returnedError ) /**< we return the first error that happened */ { returnedError = err; } } pC->pC1 = M4OSA_NULL; } /** * Close clip2, if needed */ if( M4OSA_NULL != pC->pC2 ) { err = M4VSS3GPP_intClipCleanUp(pC->pC2); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editClose: M4VSS3GPP_intClipCleanUp(C2) returns 0x%x!", err); /**< We do not return the error here because we still have stuff to free */ if( M4NO_ERROR == returnedError ) /**< we return the first error that happened */ { returnedError = err; } } pC->pC2 = M4OSA_NULL; } /** * Free the temporary YUV planes */ if( M4OSA_NULL != pC->yuv1[0].pac_data ) { free(pC->yuv1[0].pac_data); pC->yuv1[0].pac_data = M4OSA_NULL; } if( M4OSA_NULL != pC->yuv1[1].pac_data ) { free(pC->yuv1[1].pac_data); pC->yuv1[1].pac_data = M4OSA_NULL; } if( M4OSA_NULL != pC->yuv1[2].pac_data ) { free(pC->yuv1[2].pac_data); pC->yuv1[2].pac_data = M4OSA_NULL; } if( M4OSA_NULL != pC->yuv2[0].pac_data ) { free(pC->yuv2[0].pac_data); pC->yuv2[0].pac_data = M4OSA_NULL; } if( M4OSA_NULL != pC->yuv2[1].pac_data ) { free(pC->yuv2[1].pac_data); pC->yuv2[1].pac_data = M4OSA_NULL; } if( M4OSA_NULL != pC->yuv2[2].pac_data ) { free(pC->yuv2[2].pac_data); pC->yuv2[2].pac_data = M4OSA_NULL; } /* RC */ if( M4OSA_NULL != pC->yuv3[0].pac_data ) { free(pC->yuv3[0].pac_data); pC->yuv3[0].pac_data = M4OSA_NULL; } if( M4OSA_NULL != pC->yuv3[1].pac_data ) { free(pC->yuv3[1].pac_data); pC->yuv3[1].pac_data = M4OSA_NULL; } if( M4OSA_NULL != pC->yuv3[2].pac_data ) { free(pC->yuv3[2].pac_data); pC->yuv3[2].pac_data = M4OSA_NULL; } /* RC */ if( M4OSA_NULL != pC->yuv4[0].pac_data ) { free(pC->yuv4[0].pac_data); pC->yuv4[0].pac_data = M4OSA_NULL; } if( M4OSA_NULL != pC->yuv4[1].pac_data ) { free(pC->yuv4[1].pac_data); pC->yuv4[1].pac_data = M4OSA_NULL; } if( M4OSA_NULL != pC->yuv4[2].pac_data ) { free(pC->yuv4[2].pac_data); pC->yuv4[2].pac_data = M4OSA_NULL; } /** * RC Free effects list */ if( pC->pEffectsList != M4OSA_NULL ) { free(pC->pEffectsList); pC->pEffectsList = M4OSA_NULL; } /** * RC Free active effects list */ if( pC->pActiveEffectsList != M4OSA_NULL ) { free(pC->pActiveEffectsList); pC->pActiveEffectsList = M4OSA_NULL; } /** * Free active effects list */ if(pC->pActiveEffectsList1 != M4OSA_NULL) { free(pC->pActiveEffectsList1); pC->pActiveEffectsList1 = M4OSA_NULL; } if(pC->m_air_context != M4OSA_NULL) { free(pC->m_air_context); pC->m_air_context = M4OSA_NULL; } /** * Update state automaton */ pC->State = M4VSS3GPP_kEditState_CLOSED; /** * Return with no error */ M4OSA_TRACE3_1("M4VSS3GPP_editClose(): returning 0x%x", returnedError); return returnedError; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_editCleanUp() * @brief Free all resources used by the VSS edit operation. * @note The context is no more valid after this call * @param pContext (IN) VSS edit context * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only) ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_editCleanUp( M4VSS3GPP_EditContext pContext ) { M4OSA_ERR err; M4VSS3GPP_InternalEditContext *pC = (M4VSS3GPP_InternalEditContext *)pContext; M4OSA_TRACE3_1("M4VSS3GPP_editCleanUp called with pContext=0x%x", pContext); /** * Check input parameter */ if( M4OSA_NULL == pContext ) { M4OSA_TRACE1_0( "M4VSS3GPP_editCleanUp(): pContext is M4OSA_NULL, returning M4ERR_PARAMETER"); return M4ERR_PARAMETER; } /** * Close, if needed. * In "theory", we should not close if we are in CREATED state. * But in practice, in case the opening failed, it may have been partially done. * In that case we have to free some opened ressources by calling Close. */ if( M4VSS3GPP_kEditState_CLOSED != pC->State ) { M4OSA_TRACE3_0("M4VSS3GPP_editCleanUp(): calling M4VSS3GPP_editClose"); err = M4VSS3GPP_editClose(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editCleanUp(): M4VSS3GPP_editClose returns 0x%x", err); } } /** * Free the video encoder dummy AU */ if( M4OSA_NULL != pC->ewc.pDummyAuBuffer ) { free(pC->ewc.pDummyAuBuffer); pC->ewc.pDummyAuBuffer = M4OSA_NULL; } /** * Free the Audio encoder context */ if( M4OSA_NULL != pC->ewc.pAudioEncCtxt ) { err = pC->ShellAPI.pAudioEncoderGlobalFcts->pFctClose( pC->ewc.pAudioEncCtxt); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editCleanUp: pAudioEncoderGlobalFcts->pFctClose returns 0x%x", err); /**< don't return, we still have stuff to free */ } err = pC->ShellAPI.pAudioEncoderGlobalFcts->pFctCleanUp( pC->ewc.pAudioEncCtxt); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_editCleanUp: pAudioEncoderGlobalFcts->pFctCleanUp returns 0x%x", err); /**< don't return, we still have stuff to free */ } pC->ewc.pAudioEncCtxt = M4OSA_NULL; } /** * Free the shells interfaces */ M4VSS3GPP_unRegisterAllWriters(&pC->ShellAPI); M4VSS3GPP_unRegisterAllEncoders(&pC->ShellAPI); M4VSS3GPP_unRegisterAllReaders(&pC->ShellAPI); M4VSS3GPP_unRegisterAllDecoders(&pC->ShellAPI); /** * Free the settings copied in the internal context */ M4VSS3GPP_intFreeSettingsList(pC); /** * Finally, Free context */ free(pC); pC = M4OSA_NULL; /** * Return with no error */ M4OSA_TRACE3_0("M4VSS3GPP_editCleanUp(): returning M4NO_ERROR"); return M4NO_ERROR; } #ifdef WIN32 /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_GetErrorMessage() * @brief Return a string describing the given error code * @note The input string must be already allocated (and long enough!) * @param err (IN) Error code to get the description from * @param sMessage (IN/OUT) Allocated string in which the description will be copied * @return M4NO_ERROR: Input error is from the VSS3GPP module * @return M4ERR_PARAMETER:Input error is not from the VSS3GPP module ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_GetErrorMessage( M4OSA_ERR err, M4OSA_Char *sMessage ) { switch( err ) { case M4VSS3GPP_WAR_EDITING_DONE: strcpy(sMessage, "M4VSS3GPP_WAR_EDITING_DONE"); break; case M4VSS3GPP_WAR_END_OF_AUDIO_MIXING: strcpy(sMessage, "M4VSS3GPP_WAR_END_OF_AUDIO_MIXING"); break; case M4VSS3GPP_WAR_END_OF_EXTRACT_PICTURE: strcpy(sMessage, "M4VSS3GPP_WAR_END_OF_EXTRACT_PICTURE"); break; case M4VSS3GPP_ERR_INVALID_FILE_TYPE: strcpy(sMessage, "M4VSS3GPP_ERR_INVALID_FILE_TYPE"); break; case M4VSS3GPP_ERR_INVALID_EFFECT_KIND: strcpy(sMessage, "M4VSS3GPP_ERR_INVALID_EFFECT_KIND"); break; case M4VSS3GPP_ERR_INVALID_VIDEO_EFFECT_TYPE: strcpy(sMessage, "M4VSS3GPP_ERR_INVALID_VIDEO_EFFECT_TYPE"); break; case M4VSS3GPP_ERR_INVALID_AUDIO_EFFECT_TYPE: strcpy(sMessage, "M4VSS3GPP_ERR_INVALID_AUDIO_EFFECT_TYPE"); break; case M4VSS3GPP_ERR_INVALID_VIDEO_TRANSITION_TYPE: strcpy(sMessage, "M4VSS3GPP_ERR_INVALID_VIDEO_TRANSITION_TYPE"); break; case M4VSS3GPP_ERR_INVALID_AUDIO_TRANSITION_TYPE: strcpy(sMessage, "M4VSS3GPP_ERR_INVALID_AUDIO_TRANSITION_TYPE"); break; case M4VSS3GPP_ERR_INVALID_VIDEO_ENCODING_FRAME_RATE: strcpy(sMessage, "M4VSS3GPP_ERR_INVALID_VIDEO_ENCODING_FRAME_RATE"); break; case M4VSS3GPP_ERR_EXTERNAL_EFFECT_NULL: strcpy(sMessage, "M4VSS3GPP_ERR_EXTERNAL_EFFECT_NULL"); break; case M4VSS3GPP_ERR_EXTERNAL_TRANSITION_NULL: strcpy(sMessage, "M4VSS3GPP_ERR_EXTERNAL_TRANSITION_NULL"); break; case M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_DURATION: strcpy(sMessage, "M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_DURATION"); break; case M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_END_CUT: strcpy(sMessage, "M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_END_CUT"); break; case M4VSS3GPP_ERR_OVERLAPPING_TRANSITIONS: strcpy(sMessage, "M4VSS3GPP_ERR_OVERLAPPING_TRANSITIONS"); break; case M4VSS3GPP_ERR_INVALID_3GPP_FILE: strcpy(sMessage, "M4VSS3GPP_ERR_INVALID_3GPP_FILE"); break; case M4VSS3GPP_ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT: strcpy(sMessage, "M4VSS3GPP_ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT"); break; case M4VSS3GPP_ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT: strcpy(sMessage, "M4VSS3GPP_ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT"); break; case M4VSS3GPP_ERR_AMR_EDITING_UNSUPPORTED: strcpy(sMessage, "M4VSS3GPP_ERR_AMR_EDITING_UNSUPPORTED"); break; case M4VSS3GPP_ERR_INPUT_VIDEO_AU_TOO_LARGE: strcpy(sMessage, "M4VSS3GPP_ERR_INPUT_VIDEO_AU_TOO_LARGE"); break; case M4VSS3GPP_ERR_INPUT_AUDIO_AU_TOO_LARGE: strcpy(sMessage, "M4VSS3GPP_ERR_INPUT_AUDIO_AU_TOO_LARGE"); break; case M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AU: strcpy(sMessage, "M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AU"); break; case M4VSS3GPP_ERR_ENCODER_ACCES_UNIT_ERROR: strcpy(sMessage, "M4VSS3GPP_ERR_ENCODER_ACCES_UNIT_ERROR"); break; case M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_FORMAT: strcpy(sMessage, "M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_FORMAT"); break; case M4VSS3GPP_ERR_EDITING_UNSUPPORTED_H263_PROFILE: strcpy(sMessage, "M4VSS3GPP_ERR_EDITING_UNSUPPORTED_H263_PROFILE"); break; case M4VSS3GPP_ERR_EDITING_UNSUPPORTED_MPEG4_PROFILE: strcpy(sMessage, "M4VSS3GPP_ERR_EDITING_UNSUPPORTED_MPEG4_PROFILE"); break; case M4VSS3GPP_ERR_EDITING_UNSUPPORTED_MPEG4_RVLC: strcpy(sMessage, "M4VSS3GPP_ERR_EDITING_UNSUPPORTED_MPEG4_RVLC"); break; case M4VSS3GPP_ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT: strcpy(sMessage, "M4VSS3GPP_ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT"); break; case M4VSS3GPP_ERR_EDITING_NO_SUPPORTED_STREAM_IN_FILE: strcpy(sMessage, "M4VSS3GPP_ERR_EDITING_NO_SUPPORTED_STREAM_IN_FILE"); break; case M4VSS3GPP_ERR_EDITING_NO_SUPPORTED_VIDEO_STREAM_IN_FILE: strcpy(sMessage, "M4VSS3GPP_ERR_EDITING_NO_SUPPORTED_VIDEO_STREAM_IN_FILE"); break; case M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_VERSION: strcpy(sMessage, "M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_VERSION"); break; case M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_FORMAT: strcpy(sMessage, "M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_FORMAT"); break; case M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_FRAME_SIZE: strcpy(sMessage, "M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_FRAME_SIZE"); break; case M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_TIME_SCALE: strcpy(sMessage, "M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_TIME_SCALE"); break; case M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_DATA_PARTITIONING: strcpy(sMessage, "M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_DATA_PARTITIONING"); break; case M4VSS3GPP_ERR_UNSUPPORTED_MP3_ASSEMBLY: strcpy(sMessage, "M4VSS3GPP_ERR_UNSUPPORTED_MP3_ASSEMBLY"); break; case M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_STREAM_TYPE: strcpy(sMessage, "M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_STREAM_TYPE"); break; case M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_NB_OF_CHANNELS: strcpy(sMessage, "M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_NB_OF_CHANNELS"); break; case M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_SAMPLING_FREQUENCY: strcpy(sMessage, "M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_SAMPLING_FREQUENCY"); break; case M4VSS3GPP_ERR_NO_SUPPORTED_STREAM_IN_FILE: strcpy(sMessage, "M4VSS3GPP_ERR_NO_SUPPORTED_STREAM_IN_FILE"); break; case M4VSS3GPP_ERR_ADDVOLUME_EQUALS_ZERO: strcpy(sMessage, "M4VSS3GPP_ERR_ADDVOLUME_EQUALS_ZERO"); break; case M4VSS3GPP_ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION: strcpy(sMessage, "M4VSS3GPP_ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION"); break; case M4VSS3GPP_ERR_UNDEFINED_AUDIO_TRACK_FILE_FORMAT: strcpy(sMessage, "M4VSS3GPP_ERR_UNDEFINED_AUDIO_TRACK_FILE_FORMAT"); break; case M4VSS3GPP_ERR_UNSUPPORTED_ADDED_AUDIO_STREAM: strcpy(sMessage, "M4VSS3GPP_ERR_UNSUPPORTED_ADDED_AUDIO_STREAM"); break; case M4VSS3GPP_ERR_AUDIO_MIXING_UNSUPPORTED: strcpy(sMessage, "M4VSS3GPP_ERR_AUDIO_MIXING_UNSUPPORTED"); break; case M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK: strcpy(sMessage, "M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK"); break; case M4VSS3GPP_ERR_AUDIO_CANNOT_BE_MIXED: strcpy(sMessage, "M4VSS3GPP_ERR_AUDIO_CANNOT_BE_MIXED"); break; case M4VSS3GPP_ERR_INPUT_CLIP_IS_NOT_A_3GPP: strcpy(sMessage, "M4VSS3GPP_ERR_INPUT_CLIP_IS_NOT_A_3GPP"); break; case M4VSS3GPP_ERR_BEGINLOOP_HIGHER_ENDLOOP: strcpy(sMessage, "M4VSS3GPP_ERR_BEGINLOOP_HIGHER_ENDLOOP"); break; case M4VSS3GPP_ERR_H263_PROFILE_NOT_SUPPORTED: strcpy(sMessage, "M4VSS3GPP_ERR_H263_PROFILE_NOT_SUPPORTED"); break; case M4VSS3GPP_ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE: strcpy(sMessage, "M4VSS3GPP_ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE"); break; default: /**< Not a VSS3GPP error */ strcpy(sMessage, ""); return M4ERR_PARAMETER; } return M4NO_ERROR; } #endif /* WIN32 */ /********************************************************/ /********************************************************/ /********************************************************/ /**************** STATIC FUNCTIONS ******************/ /********************************************************/ /********************************************************/ /********************************************************/ /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_intClipSettingsSanityCheck() * @brief Simplify the given clip settings * @note This function may modify the given structure * @param pClip (IN/OUT) Clip settings * @return M4NO_ERROR: No error * @return M4VSS3GPP_ERR_EXTERNAL_EFFECT_NULL: ****************************************************************************** */ static M4OSA_ERR M4VSS3GPP_intClipSettingsSanityCheck( M4VSS3GPP_ClipSettings *pClip ) { M4OSA_UInt8 uiFx; M4OSA_UInt32 uiClipActualDuration; /**< the clip duration once the cuts are done */ M4OSA_UInt32 uiDuration; M4VSS3GPP_EffectSettings *pFx; /** * If begin cut is too far, return an error */ uiDuration = pClip->ClipProperties.uiClipDuration; if( pClip->uiBeginCutTime > uiDuration ) { M4OSA_TRACE1_2( "M4VSS3GPP_intClipSettingsSanityCheck: %d > %d,\ returning M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_DURATION", pClip->uiBeginCutTime, uiDuration); return M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_DURATION; } /** * If end cut is too far, set to zero (it means no end cut) */ if( pClip->uiEndCutTime > uiDuration ) { pClip->uiEndCutTime = 0; } /** * Compute actual clip duration (once cuts are done) */ if( 0 == pClip->uiEndCutTime ) { /** * No end cut */ uiClipActualDuration = uiDuration - pClip->uiBeginCutTime; } else { if( pClip->uiBeginCutTime >= pClip->uiEndCutTime ) { M4OSA_TRACE1_2( "M4VSS3GPP_intClipSettingsSanityCheck: %d > %d,\ returning M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_END_CUT", pClip->uiBeginCutTime, pClip->uiEndCutTime); return M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_END_CUT; } uiClipActualDuration = pClip->uiEndCutTime - pClip->uiBeginCutTime; } return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_intTransitionSettingsSanityCheck() * @brief Simplify the given transition settings * @note This function may modify the given structure * @param pTransition (IN/OUT) Transition settings * @return M4NO_ERROR: No error * @return M4VSS3GPP_ERR_EXTERNAL_TRANSITION_NULL: ****************************************************************************** */ static M4OSA_ERR M4VSS3GPP_intTransitionSettingsSanityCheck( M4VSS3GPP_TransitionSettings *pTransition ) { /** * No transition */ if( 0 == pTransition->uiTransitionDuration ) { pTransition->VideoTransitionType = M4VSS3GPP_kVideoTransitionType_None; pTransition->AudioTransitionType = M4VSS3GPP_kAudioTransitionType_None; } else if( ( M4VSS3GPP_kVideoTransitionType_None == pTransition->VideoTransitionType) && (M4VSS3GPP_kAudioTransitionType_None == pTransition->AudioTransitionType) ) { pTransition->uiTransitionDuration = 0; } /** * Check external transition function is set */ if( ( pTransition->VideoTransitionType >= M4VSS3GPP_kVideoTransitionType_External) && (M4OSA_NULL == pTransition->ExtVideoTransitionFct) ) { return M4VSS3GPP_ERR_EXTERNAL_TRANSITION_NULL; } /** * Set minimal transition duration */ if( ( pTransition->uiTransitionDuration > 0) && (pTransition->uiTransitionDuration < M4VSS3GPP_MINIMAL_TRANSITION_DURATION) ) { pTransition->uiTransitionDuration = M4VSS3GPP_MINIMAL_TRANSITION_DURATION; } return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_intFreeSettingsList() * @brief Free the settings copied in the internal context * @param pC (IN/OUT) Internal edit context ****************************************************************************** */ static M4OSA_Void M4VSS3GPP_intFreeSettingsList( M4VSS3GPP_InternalEditContext *pC ) { M4OSA_UInt32 i; /** * Free the settings list */ if( M4OSA_NULL != pC->pClipList ) { for ( i = 0; i < pC->uiClipNumber; i++ ) { M4VSS3GPP_editFreeClipSettings(&(pC->pClipList[i])); } free(pC->pClipList); pC->pClipList = M4OSA_NULL; } /** * Free the transition list */ if( M4OSA_NULL != pC->pTransitionList ) { free(pC->pTransitionList); pC->pTransitionList = M4OSA_NULL; } } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_intCreateMP3OutputFile() * @brief Creates and prepare the output MP file * @param pC (IN/OUT) Internal edit context ****************************************************************************** */ static M4OSA_ERR M4VSS3GPP_intCreateMP3OutputFile( M4VSS3GPP_InternalEditContext *pC, M4OSA_Void *pOutputFile ) { M4OSA_ERR err; err = pC->pOsaFileWritPtr->openWrite(&pC->ewc.p3gpWriterContext, pOutputFile, M4OSA_kFileWrite); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intCreateMP3OutputFile: WriteOpen returns 0x%x!", err); return err; } return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_intCreate3GPPOutputFile() * @brief Creates and prepare the output MP3 file * @note Creates the writer, Creates the output file, Adds the streams, Readies the writing process * @param pC (IN/OUT) Internal edit context ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_intCreate3GPPOutputFile( M4VSS3GPP_EncodeWriteContext *pC_ewc, M4VSS3GPP_MediaAndCodecCtxt *pC_ShellAPI, M4OSA_FileWriterPointer *pOsaFileWritPtr, M4OSA_Void *pOutputFile, M4OSA_FileReadPointer *pOsaFileReadPtr, M4OSA_Void *pTempFile, M4OSA_UInt32 maxOutputFileSize ) { M4OSA_ERR err; M4OSA_UInt32 uiVersion; M4SYS_StreamIDValue temp; M4OSA_TRACE3_2( "M4VSS3GPP_intCreate3GPPOutputFile called with pC_ewc=0x%x, pOutputFile=0x%x", pC_ewc, pOutputFile); /** * Check input parameter */ M4OSA_DEBUG_IF2((M4OSA_NULL == pC_ewc), M4ERR_PARAMETER, "M4VSS3GPP_intCreate3GPPOutputFile: pC_ewc is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pOutputFile), M4ERR_PARAMETER, "M4VSS3GPP_intCreate3GPPOutputFile: pOutputFile is M4OSA_NULL"); /* Set writer */ err = M4VSS3GPP_setCurrentWriter(pC_ShellAPI, M4VIDEOEDITING_kFileType_3GPP); M4ERR_CHECK_RETURN(err); /** * Create the output file */ err = pC_ShellAPI->pWriterGlobalFcts->pFctOpen(&pC_ewc->p3gpWriterContext, pOutputFile, pOsaFileWritPtr, pTempFile, pOsaFileReadPtr); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile: pWriterGlobalFcts->pFctOpen returns 0x%x!", err); return err; } /** * Set the signature option of the writer */ err = pC_ShellAPI->pWriterGlobalFcts->pFctSetOption(pC_ewc->p3gpWriterContext, M4WRITER_kEmbeddedString, (M4OSA_DataOption)"NXP-SW : VSS "); if( ( M4NO_ERROR != err) && (((M4OSA_UInt32)M4ERR_BAD_OPTION_ID) != err) ) /* this option may not be implemented by some writers */ { M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile:\ pWriterGlobalFcts->pFctSetOption(M4WRITER_kEmbeddedString) returns 0x%x!", err); return err; } /*11/12/2008 CR3283 MMS use case for VideoArtist: Set the max output file size option in the writer so that the output file will be smaller than the given file size limitation*/ if( maxOutputFileSize > 0 ) { err = pC_ShellAPI->pWriterGlobalFcts->pFctSetOption( pC_ewc->p3gpWriterContext, M4WRITER_kMaxFileSize, &maxOutputFileSize); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile:\ writer set option M4WRITER_kMaxFileSize returns 0x%x", err); return err; } } /** * Set the version option of the writer */ uiVersion = (M4VIDEOEDITING_VERSION_MAJOR * 100 + M4VIDEOEDITING_VERSION_MINOR * 10 + M4VIDEOEDITING_VERSION_REVISION); err = pC_ShellAPI->pWriterGlobalFcts->pFctSetOption(pC_ewc->p3gpWriterContext, M4WRITER_kEmbeddedVersion, (M4OSA_DataOption) &uiVersion); if( ( M4NO_ERROR != err) && (((M4OSA_UInt32)M4ERR_BAD_OPTION_ID) != err) ) /* this option may not be implemented by some writers */ { M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile:\ pWriterGlobalFcts->pFctSetOption(M4WRITER_kEmbeddedVersion) returns 0x%x!", err); return err; } if( M4SYS_kVideoUnknown != pC_ewc->VideoStreamType ) { /** * Set the video stream properties */ pC_ewc->WriterVideoStreamInfo.height = pC_ewc->uiVideoHeight; pC_ewc->WriterVideoStreamInfo.width = pC_ewc->uiVideoWidth; pC_ewc->WriterVideoStreamInfo.fps = 0.0; /**< Not used by the shell/core writer */ pC_ewc->WriterVideoStreamInfo.Header.pBuf = pC_ewc->pVideoOutputDsi; /**< Previously computed output DSI */ pC_ewc->WriterVideoStreamInfo.Header.Size = pC_ewc-> uiVideoOutputDsiSize; /**< Previously computed output DSI size */ pC_ewc->WriterVideoStream.streamType = pC_ewc->VideoStreamType; switch( pC_ewc->VideoStreamType ) { case M4SYS_kMPEG_4: case M4SYS_kH263: case M4SYS_kH264: /**< We HAVE to put a value here... */ pC_ewc->WriterVideoStream.averageBitrate = pC_ewc->uiVideoBitrate; pC_ewc->WriterVideoStream.maxBitrate = pC_ewc->uiVideoBitrate; break; default: M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile: unknown input video format (0x%x),\ returning M4VSS3GPP_ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT!", pC_ewc->VideoStreamType); return M4VSS3GPP_ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT; } pC_ewc->WriterVideoStream.streamID = M4VSS3GPP_WRITER_VIDEO_STREAM_ID; pC_ewc->WriterVideoStream.timeScale = 0; /**< Not used by the shell/core writer */ pC_ewc->WriterVideoStream.profileLevel = 0; /**< Not used by the shell/core writer */ pC_ewc->WriterVideoStream.duration = 0; /**< Not used by the shell/core writer */ pC_ewc->WriterVideoStream.decoderSpecificInfoSize = sizeof(M4WRITER_StreamVideoInfos); pC_ewc->WriterVideoStream.decoderSpecificInfo = (M4OSA_MemAddr32) &(pC_ewc->WriterVideoStreamInfo); /** * Add the video stream */ err = pC_ShellAPI->pWriterGlobalFcts->pFctAddStream( pC_ewc->p3gpWriterContext, &pC_ewc->WriterVideoStream); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile:\ pWriterGlobalFcts->pFctAddStream(video) returns 0x%x!", err); return err; } /** * Update AU properties for video stream */ pC_ewc->WriterVideoAU.attribute = AU_RAP; pC_ewc->WriterVideoAU.CTS = 0; pC_ewc->WriterVideoAU.DTS = 0; /** Reset time */ pC_ewc->WriterVideoAU.frag = M4OSA_NULL; pC_ewc->WriterVideoAU.nbFrag = 0; /** No fragment */ pC_ewc->WriterVideoAU.size = 0; pC_ewc->WriterVideoAU.dataAddress = M4OSA_NULL; pC_ewc->WriterVideoAU.stream = &(pC_ewc->WriterVideoStream); /** * Set the writer max video AU size */ pC_ewc->uiVideoMaxAuSize = (M4OSA_UInt32)(1.5F *(M4OSA_Float)(pC_ewc->WriterVideoStreamInfo.width * pC_ewc->WriterVideoStreamInfo.height) * M4VSS3GPP_VIDEO_MIN_COMPRESSION_RATIO); temp.streamID = M4VSS3GPP_WRITER_VIDEO_STREAM_ID; temp.value = pC_ewc->uiVideoMaxAuSize; err = pC_ShellAPI->pWriterGlobalFcts->pFctSetOption( pC_ewc->p3gpWriterContext, (M4OSA_UInt32)M4WRITER_kMaxAUSize, (M4OSA_DataOption) &temp); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile:\ pWriterGlobalFcts->pFctSetOption(M4WRITER_kMaxAUSize, video) returns 0x%x!", err); return err; } /** * Set the writer max video chunk size */ temp.streamID = M4VSS3GPP_WRITER_VIDEO_STREAM_ID; temp.value = (M4OSA_UInt32)(pC_ewc->uiVideoMaxAuSize \ * M4VSS3GPP_VIDEO_AU_SIZE_TO_CHUNCK_SIZE_RATIO); /**< from max AU size to max Chunck size */ err = pC_ShellAPI->pWriterGlobalFcts->pFctSetOption( pC_ewc->p3gpWriterContext, (M4OSA_UInt32)M4WRITER_kMaxChunckSize, (M4OSA_DataOption) &temp); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile:\ pWriterGlobalFcts->pFctSetOption(M4WRITER_kMaxAUSize, video) returns 0x%x!", err); return err; } } if( M4SYS_kAudioUnknown != pC_ewc->AudioStreamType ) { M4WRITER_StreamAudioInfos streamAudioInfo; streamAudioInfo.nbSamplesPerSec = 0; /**< unused by our shell writer */ streamAudioInfo.nbBitsPerSample = 0; /**< unused by our shell writer */ streamAudioInfo.nbChannels = 1; /**< unused by our shell writer */ if( pC_ewc->pAudioOutputDsi != M4OSA_NULL ) { /* If we copy the stream from the input, we copy its DSI */ streamAudioInfo.Header.Size = pC_ewc->uiAudioOutputDsiSize; streamAudioInfo.Header.pBuf = pC_ewc->pAudioOutputDsi; } else { /* Writer will put a default DSI */ streamAudioInfo.Header.Size = 0; streamAudioInfo.Header.pBuf = M4OSA_NULL; } pC_ewc->WriterAudioStream.streamID = M4VSS3GPP_WRITER_AUDIO_STREAM_ID; pC_ewc->WriterAudioStream.streamType = pC_ewc->AudioStreamType; pC_ewc->WriterAudioStream.duration = 0; /**< Not used by the shell/core writer */ pC_ewc->WriterAudioStream.profileLevel = 0; /**< Not used by the shell/core writer */ pC_ewc->WriterAudioStreamInfo.nbSamplesPerSec = pC_ewc->uiSamplingFrequency; pC_ewc->WriterAudioStream.timeScale = pC_ewc->uiSamplingFrequency; pC_ewc->WriterAudioStreamInfo.nbChannels = (M4OSA_UInt16)pC_ewc->uiNbChannels; pC_ewc->WriterAudioStreamInfo.nbBitsPerSample = 0; /**< Not used by the shell/core writer */ /** * Add the audio stream */ switch( pC_ewc->AudioStreamType ) { case M4SYS_kAMR: pC_ewc->WriterAudioStream.averageBitrate = 0; /**< It is not used by the shell, the DSI is taken into account instead */ pC_ewc->WriterAudioStream.maxBitrate = 0; /**< Not used by the shell/core writer */ break; case M4SYS_kAAC: pC_ewc->WriterAudioStream.averageBitrate = pC_ewc->uiAudioBitrate; pC_ewc->WriterAudioStream.maxBitrate = pC_ewc->uiAudioBitrate; break; case M4SYS_kEVRC: pC_ewc->WriterAudioStream.averageBitrate = 0; /**< It is not used by the shell, the DSI is taken into account instead */ pC_ewc->WriterAudioStream.maxBitrate = 0; /**< Not used by the shell/core writer */ break; case M4SYS_kMP3: /**< there can't be MP3 track in 3GPP file -> error */ default: M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile: unknown output audio format (0x%x),\ returning M4VSS3GPP_ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT!", pC_ewc->AudioStreamType); return M4VSS3GPP_ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT; } /** * Our writer shell interface is a little tricky: we put M4WRITER_StreamAudioInfos in the DSI pointer... */ pC_ewc->WriterAudioStream.decoderSpecificInfo = (M4OSA_MemAddr32) &streamAudioInfo; /** * Link the AU and the stream */ pC_ewc->WriterAudioAU.stream = &(pC_ewc->WriterAudioStream); pC_ewc->WriterAudioAU.dataAddress = M4OSA_NULL; pC_ewc->WriterAudioAU.size = 0; pC_ewc->WriterAudioAU.CTS = -pC_ewc->iSilenceFrameDuration; /** Reset time */ pC_ewc->WriterAudioAU.DTS = 0; pC_ewc->WriterAudioAU.attribute = 0; pC_ewc->WriterAudioAU.nbFrag = 0; /** No fragment */ pC_ewc->WriterAudioAU.frag = M4OSA_NULL; err = pC_ShellAPI->pWriterGlobalFcts->pFctAddStream( pC_ewc->p3gpWriterContext, &pC_ewc->WriterAudioStream); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile:\ pWriterGlobalFcts->pFctAddStream(audio) returns 0x%x!", err); return err; } /** * Set the writer max audio AU size */ pC_ewc->uiAudioMaxAuSize = M4VSS3GPP_AUDIO_MAX_AU_SIZE; temp.streamID = M4VSS3GPP_WRITER_AUDIO_STREAM_ID; temp.value = pC_ewc->uiAudioMaxAuSize; err = pC_ShellAPI->pWriterGlobalFcts->pFctSetOption( pC_ewc->p3gpWriterContext, (M4OSA_UInt32)M4WRITER_kMaxAUSize, (M4OSA_DataOption) &temp); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile:\ pWriterGlobalFcts->pFctSetOption(M4WRITER_kMaxAUSize, audio) returns 0x%x!", err); return err; } /** * Set the writer max audio chunck size */ temp.streamID = M4VSS3GPP_WRITER_AUDIO_STREAM_ID; temp.value = M4VSS3GPP_AUDIO_MAX_CHUNCK_SIZE; err = pC_ShellAPI->pWriterGlobalFcts->pFctSetOption( pC_ewc->p3gpWriterContext, (M4OSA_UInt32)M4WRITER_kMaxChunckSize, (M4OSA_DataOption) &temp); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile:\ pWriterGlobalFcts->pFctSetOption(M4WRITER_kMaxAUSize, audio) returns 0x%x!", err); return err; } } /** * All streams added, we're now ready to write */ err = pC_ShellAPI->pWriterGlobalFcts->pFctStartWriting( pC_ewc->p3gpWriterContext); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intCreate3GPPOutputFile:\ pWriterGlobalFcts->pFctStartWriting() returns 0x%x!", err); return err; } /** * Return with no error */ M4OSA_TRACE3_0("M4VSS3GPP_intCreate3GPPOutputFile(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_intComputeOutputVideoAndAudioDsi() * @brief Generate a H263 or MPEG-4 decoder specific info compatible with all input video * tracks. Copy audio dsi from master clip. * @param pC (IN/OUT) Internal edit context ****************************************************************************** */ static M4OSA_ERR M4VSS3GPP_intComputeOutputVideoAndAudioDsi( M4VSS3GPP_InternalEditContext *pC, M4OSA_UInt8 uiMasterClip ) { M4OSA_Int32 iResynchMarkerDsiIndex; M4_StreamHandler *pStreamForDsi; M4VSS3GPP_ClipContext *pClip; M4OSA_ERR err; M4OSA_UInt32 i; M4DECODER_MPEG4_DecoderConfigInfo DecConfigInfo; M4DECODER_VideoSize dummySize; M4OSA_Bool bGetDSiFromEncoder = M4OSA_FALSE; M4ENCODER_Header *encHeader; M4SYS_StreamIDmemAddr streamHeader; pStreamForDsi = M4OSA_NULL; pClip = M4OSA_NULL; /** * H263 case */ if( M4SYS_kH263 == pC->ewc.VideoStreamType ) { /** * H263 output DSI is always 7 bytes */ pC->ewc.uiVideoOutputDsiSize = 7; pC->ewc.pVideoOutputDsi = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(pC->ewc.uiVideoOutputDsiSize, M4VSS3GPP, (M4OSA_Char *)"pC->ewc.pVideoOutputDsi (H263)"); if( M4OSA_NULL == pC->ewc.pVideoOutputDsi ) { M4OSA_TRACE1_0( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi():\ unable to allocate pVideoOutputDsi (H263), returning M4ERR_ALLOC"); return M4ERR_ALLOC; } /** * (We override the input vendor info. * At least we know that nothing special will be tried with PHLP-stamped edited streams...) */ pC->ewc.pVideoOutputDsi[0] = 'P'; pC->ewc.pVideoOutputDsi[1] = 'H'; pC->ewc.pVideoOutputDsi[2] = 'L'; pC->ewc.pVideoOutputDsi[3] = 'P'; /** * Decoder version is 0 */ pC->ewc.pVideoOutputDsi[4] = 0; /** * Level is the sixth byte in the DSI */ pC->ewc.pVideoOutputDsi[5] = pC->xVSS.outputVideoLevel; /** * Profile is the seventh byte in the DSI*/ pC->ewc.pVideoOutputDsi[6] = pC->xVSS.outputVideoProfile; } /** * MPEG-4 case */ else if( M4SYS_kMPEG_4 == pC->ewc.VideoStreamType || M4SYS_kH264 == pC->ewc.VideoStreamType) { /* For MPEG4 and H.264 encoder case * Fetch the DSI from the shell video encoder, and feed it to the writer before closing it. */ M4OSA_TRACE1_0( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi: get DSI for H264 stream"); if( M4OSA_NULL == pC->ewc.pEncContext ) { M4OSA_TRACE1_0( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi: pC->ewc.pEncContext is NULL"); err = M4VSS3GPP_intCreateVideoEncoder(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi:\ M4VSS3GPP_intCreateVideoEncoder returned error 0x%x", err); } } if( M4OSA_NULL != pC->ewc.pEncContext ) { err = pC->ShellAPI.pVideoEncoderGlobalFcts->pFctGetOption( pC->ewc.pEncContext, M4ENCODER_kOptionID_EncoderHeader, (M4OSA_DataOption) &encHeader); if( ( M4NO_ERROR != err) || (M4OSA_NULL == encHeader->pBuf) ) { M4OSA_TRACE1_1( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi:\ failed to get the encoder header (err 0x%x)", err); M4OSA_TRACE1_2( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi: encHeader->pBuf=0x%x, size=0x%x", encHeader->pBuf, encHeader->Size); } else { M4OSA_TRACE1_0( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi:\ send DSI for video stream to 3GP writer"); /** * Allocate and copy the new DSI */ pC->ewc.pVideoOutputDsi = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(encHeader->Size, M4VSS3GPP, (M4OSA_Char *)"pC->ewc.pVideoOutputDsi (H264)"); if( M4OSA_NULL == pC->ewc.pVideoOutputDsi ) { M4OSA_TRACE1_0( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi():\ unable to allocate pVideoOutputDsi, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } pC->ewc.uiVideoOutputDsiSize = (M4OSA_UInt16)encHeader->Size; memcpy((void *)pC->ewc.pVideoOutputDsi, (void *)encHeader->pBuf, encHeader->Size); } err = M4VSS3GPP_intDestroyVideoEncoder(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi:\ M4VSS3GPP_intDestroyVideoEncoder returned error 0x%x", err); } } else { M4OSA_TRACE1_0( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi:\ pC->ewc.pEncContext is NULL, cannot get the DSI"); } } pStreamForDsi = M4OSA_NULL; pClip = M4OSA_NULL; /* Compute Audio DSI */ if( M4SYS_kAudioUnknown != pC->ewc.AudioStreamType ) { if( uiMasterClip == 0 ) { /* Clip is already opened */ pStreamForDsi = &(pC->pC1->pAudioStream->m_basicProperties); } else { /** * We can use the fast open mode to get the DSI */ err = M4VSS3GPP_intClipInit(&pClip, pC->pOsaFileReadPtr); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi:\ M4VSS3GPP_intClipInit() returns 0x%x!", err); if( pClip != M4OSA_NULL ) { M4VSS3GPP_intClipCleanUp(pClip); } return err; } err = M4VSS3GPP_intClipOpen(pClip, &pC->pClipList[uiMasterClip], M4OSA_FALSE, M4OSA_TRUE, M4OSA_TRUE); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi:\ M4VSS3GPP_intClipOpen() returns 0x%x!", err); M4VSS3GPP_intClipCleanUp(pClip); return err; } pStreamForDsi = &(pClip->pAudioStream->m_basicProperties); } /** * Allocate and copy the new DSI */ pC->ewc.pAudioOutputDsi = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc( pStreamForDsi->m_decoderSpecificInfoSize, M4VSS3GPP, (M4OSA_Char *)"pC->ewc.pAudioOutputDsi"); if( M4OSA_NULL == pC->ewc.pAudioOutputDsi ) { M4OSA_TRACE1_0( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi():\ unable to allocate pAudioOutputDsi, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } pC->ewc.uiAudioOutputDsiSize = (M4OSA_UInt16)pStreamForDsi->m_decoderSpecificInfoSize; memcpy((void *)pC->ewc.pAudioOutputDsi, (void *)pStreamForDsi->m_pDecoderSpecificInfo, pC->ewc.uiAudioOutputDsiSize); /** * If a clip has been temporarily opened to get its DSI, close it */ if( M4OSA_NULL != pClip ) { err = M4VSS3GPP_intClipCleanUp(pClip); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi:\ M4VSS3GPP_intClipCleanUp() returns 0x%x!", err); return err; } } } /** * Return with no error */ M4OSA_TRACE3_0( "M4VSS3GPP_intComputeOutputVideoAndAudioDsi(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_intSwitchToNextClip() * @brief Switch from the current clip to the next one * @param pC (IN/OUT) Internal edit context ****************************************************************************** */ static M4OSA_ERR M4VSS3GPP_intSwitchToNextClip( M4VSS3GPP_InternalEditContext *pC ) { M4OSA_ERR err; if( M4OSA_NULL != pC->pC1 ) { if (M4OSA_NULL != pC->pC1->m_pPreResizeFrame) { if (M4OSA_NULL != pC->pC1->m_pPreResizeFrame[0].pac_data) { free(pC->pC1->m_pPreResizeFrame[0].pac_data); pC->pC1->m_pPreResizeFrame[0].pac_data = M4OSA_NULL; } if (M4OSA_NULL != pC->pC1->m_pPreResizeFrame[1].pac_data) { free(pC->pC1->m_pPreResizeFrame[1].pac_data); pC->pC1->m_pPreResizeFrame[1].pac_data = M4OSA_NULL; } if (M4OSA_NULL != pC->pC1->m_pPreResizeFrame[2].pac_data) { free(pC->pC1->m_pPreResizeFrame[2].pac_data); pC->pC1->m_pPreResizeFrame[2].pac_data = M4OSA_NULL; } free(pC->pC1->m_pPreResizeFrame); pC->pC1->m_pPreResizeFrame = M4OSA_NULL; } /** * Close the current first clip */ err = M4VSS3GPP_intClipCleanUp(pC->pC1); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intSwitchToNextClip: M4VSS3GPP_intClipCleanUp(C1) returns 0x%x!", err); return err; } /** * increment clip counter */ pC->uiCurrentClip++; } /** * Check if we reached the last clip */ if( pC->uiCurrentClip >= pC->uiClipNumber ) { pC->pC1 = M4OSA_NULL; pC->State = M4VSS3GPP_kEditState_FINISHED; M4OSA_TRACE1_0( "M4VSS3GPP_intSwitchToNextClip:\ M4VSS3GPP_intClipClose(C1) returns M4VSS3GPP_WAR_EDITING_DONE"); return M4VSS3GPP_WAR_EDITING_DONE; } /** * If the next clip has already be opened, set it as first clip */ if( M4OSA_NULL != pC->pC2 ) { pC->pC1 = pC->pC2; if(M4OSA_NULL != pC->pC2->m_pPreResizeFrame) { pC->pC1->m_pPreResizeFrame = pC->pC2->m_pPreResizeFrame; } pC->pC2 = M4OSA_NULL; pC->bClip1ActiveFramingEffect = pC->bClip2ActiveFramingEffect; pC->bClip2ActiveFramingEffect = M4OSA_FALSE; } /** * else open it */ else { err = M4VSS3GPP_intOpenClip(pC, &pC->pC1, &pC->pClipList[pC->uiCurrentClip]); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intSwitchToNextClip: M4VSS3GPP_intOpenClip() returns 0x%x!", err); return err; } /** * If the second clip has not been opened yet, that means that there has been no transition. * So both output video and audio times are OK. * So we can set both video2 and audio offsets */ /** * Add current video output CTS to the clip video offset */ // Decorrelate input and output encoding timestamp to handle encoder prefetch pC->pC1->iVoffset += (M4OSA_UInt32)pC->ewc.dInputVidCts; /** * Add current audio output CTS to the clip audio offset */ pC->pC1->iAoffset += (M4OSA_UInt32)(pC->ewc.dATo * pC->ewc.scale_audio + 0.5); /** * 2005-03-24: BugFix for audio-video synchro: * There may be a portion of the duration of an audio AU of desynchro at each assembly. * It leads to an audible desynchro when there are a lot of clips assembled. * This bug fix allows to resynch the audio track when the delta is higher * than one audio AU duration. * We Step one AU in the second clip and we change the audio offset accordingly. */ if( ( pC->pC1->iAoffset - (M4OSA_Int32)(pC->pC1->iVoffset *pC->pC1->scale_audio + 0.5)) > pC->ewc.iSilenceFrameDuration ) { /** * Advance one AMR frame */ err = M4VSS3GPP_intClipReadNextAudioFrame(pC->pC1); if( M4OSA_ERR_IS_ERROR(err) ) { M4OSA_TRACE1_1( "M4VSS3GPP_intSwitchToNextClip:\ M4VSS3GPP_intClipReadNextAudioFrame returns 0x%x!", err); return err; } /** * Update audio offset accordingly*/ pC->pC1->iAoffset -= pC->ewc.iSilenceFrameDuration; } } /** * Init starting state for this clip processing */ if( M4SYS_kMP3 == pC->ewc.AudioStreamType ) { /** * In the MP3 case we use a special audio state */ pC->State = M4VSS3GPP_kEditState_MP3_JUMP; } else { /** * We start with the video processing */ pC->State = M4VSS3GPP_kEditState_VIDEO; if( pC->Vstate != M4VSS3GPP_kEditVideoState_TRANSITION ) { /* if not a transition then reset previous video state */ pC->Vstate = M4VSS3GPP_kEditVideoState_READ_WRITE; } } /* The flags are set to false at the beginning of every clip */ pC->m_bClipExternalHasStarted = M4OSA_FALSE; pC->bEncodeTillEoF = M4OSA_FALSE; /** * Return with no error */ M4OSA_TRACE3_0("M4VSS3GPP_intSwitchToNextClip(): returning M4NO_ERROR"); /* RC: to know when a file has been processed */ return M4VSS3GPP_WAR_SWITCH_CLIP; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_intReachedEndOfVideo() * @brief Do what to do when the end of a clip video track is reached * @note If there is audio on the current clip, process it, else switch to the next clip * @param pC (IN/OUT) Internal edit context ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_intReachedEndOfVideo( M4VSS3GPP_InternalEditContext *pC ) { M4OSA_ERR err; /** * Video is done for this clip, now we do the audio */ if( M4SYS_kAudioUnknown != pC->ewc.AudioStreamType ) { pC->State = M4VSS3GPP_kEditState_AUDIO; } else { /** * Clip done, do the next one */ err = M4VSS3GPP_intSwitchToNextClip(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intReachedEndOfVideo: M4VSS3GPP_intSwitchToNextClip() returns 0x%x", err); return err; } } /** * Return with no error */ M4OSA_TRACE3_0("M4VSS3GPP_intReachedEndOfVideo(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_intReachedEndOfAudio() * @brief Do what to do when the end of a clip audio track is reached * @param pC (IN/OUT) Internal edit context ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_intReachedEndOfAudio( M4VSS3GPP_InternalEditContext *pC ) { M4OSA_ERR err; /** * Clip done, do the next one */ err = M4VSS3GPP_intSwitchToNextClip(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intReachedEndOfAudio: M4VSS3GPP_intSwitchToNextClip() returns 0x%x", err); return err; } /** * Start with the video */ if( M4SYS_kVideoUnknown != pC->ewc.VideoStreamType ) { pC->State = M4VSS3GPP_kEditState_VIDEO; } /** * Return with no error */ M4OSA_TRACE3_0("M4VSS3GPP_intReachedEndOfAudio(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_intOpenClip() * @brief Open next clip * @param pC (IN/OUT) Internal edit context ****************************************************************************** */ M4OSA_ERR M4VSS3GPP_intOpenClip( M4VSS3GPP_InternalEditContext *pC, M4VSS3GPP_ClipContext ** hClip, M4VSS3GPP_ClipSettings *pClipSettings ) { M4OSA_ERR err; M4VSS3GPP_ClipContext *pClip; /**< shortcut */ M4VIDEOEDITING_ClipProperties *pClipProperties = M4OSA_NULL; M4OSA_Int32 iCts; M4OSA_UInt32 i; M4OSA_TRACE2_1("M4VSS3GPP_intOpenClip: \"%s\"", (M4OSA_Char *)pClipSettings->pFile); err = M4VSS3GPP_intClipInit(hClip, pC->pOsaFileReadPtr); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intOpenClip: M4VSS3GPP_intClipInit() returns 0x%x!", err); if( *hClip != M4OSA_NULL ) { M4VSS3GPP_intClipCleanUp(*hClip); } return err; } /** * Set shortcut */ pClip = *hClip; if (pClipSettings->FileType == M4VIDEOEDITING_kFileType_ARGB8888 ) { pClipProperties = &pClipSettings->ClipProperties; pClip->pSettings = pClipSettings; pClip->iEndTime = pClipSettings->uiEndCutTime; } err = M4VSS3GPP_intClipOpen(pClip, pClipSettings, M4OSA_FALSE, M4OSA_FALSE, M4OSA_FALSE); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4VSS3GPP_intOpenClip: \ M4VSS3GPP_intClipOpen() returns 0x%x!", err); M4VSS3GPP_intClipCleanUp(pClip); *hClip = M4OSA_NULL; return err; } if (pClipSettings->FileType != M4VIDEOEDITING_kFileType_ARGB8888 ) { pClipProperties = &pClip->pSettings->ClipProperties; } /** * Copy common 'silence frame stuff' to ClipContext */ pClip->uiSilencePcmSize = pC->ewc.uiSilencePcmSize; pClip->pSilenceFrameData = pC->ewc.pSilenceFrameData; pClip->uiSilenceFrameSize = pC->ewc.uiSilenceFrameSize; pClip->iSilenceFrameDuration = pC->ewc.iSilenceFrameDuration; pClip->scale_audio = pC->ewc.scale_audio; pClip->iAudioFrameCts = -pClip->iSilenceFrameDuration; /* Reset time */ /** * If the audio track is not compatible with the output audio format, * we remove it. So it will be replaced by silence */ if( M4OSA_FALSE == pClipProperties->bAudioIsCompatibleWithMasterClip ) { M4VSS3GPP_intClipDeleteAudioTrack(pClip); } /** * Actual begin cut */ if( 0 == pClipSettings->uiBeginCutTime ) { pClip->iVoffset = 0; pClip->iAoffset = 0; pClip->iActualVideoBeginCut = 0; pClip->iActualAudioBeginCut = 0; } else if(pClipSettings->FileType != M4VIDEOEDITING_kFileType_ARGB8888) { if( M4SYS_kVideoUnknown != pC->ewc.VideoStreamType ) { /** * Jump the video to the target begin cut to get the actual begin cut value */ pClip->iActualVideoBeginCut = (M4OSA_Int32)pClipSettings->uiBeginCutTime; iCts = pClip->iActualVideoBeginCut; err = pClip->ShellAPI.m_pReader->m_pFctJump(pClip->pReaderContext, (M4_StreamHandler *)pClip->pVideoStream, &iCts); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intOpenClip: m_pFctJump(V) returns 0x%x!", err); return err; } /** * Update clip offset with the video begin cut */ pClip->iVoffset = -pClip->iActualVideoBeginCut; } if( M4SYS_kAudioUnknown != pC->ewc.AudioStreamType ) { /** * Jump the audio to the video actual begin cut */ if( M4VIDEOEDITING_kMP3 != pClipProperties->AudioStreamType ) { pClip->iActualAudioBeginCut = pClip->iActualVideoBeginCut; iCts = (M4OSA_Int32)(pClip->iActualAudioBeginCut * pClip->scale_audio + 0.5); err = M4VSS3GPP_intClipJumpAudioAt(pClip, &iCts); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4VSS3GPP_intOpenClip: M4VSS3GPP_intClipJumpAudioAt(A) returns 0x%x!", err); return err; } /** * Update clip offset with the audio begin cut */ pClip->iAoffset = -iCts; } else { /** * For the MP3, the jump is not done because of the VBR, it could be not enough accurate */ pClip->iActualAudioBeginCut = (M4OSA_Int32)pClipSettings->uiBeginCutTime; } } } if( M4SYS_kVideoUnknown != pC->ewc.VideoStreamType ) { if ((pClipSettings->FileType != M4VIDEOEDITING_kFileType_ARGB8888 )) { /** * Read the first Video AU of the clip */ err = pClip->ShellAPI.m_pReaderDataIt->m_pFctGetNextAu( pClip->pReaderContext, (M4_StreamHandler *)pClip->pVideoStream, &pClip->VideoAU); if( M4WAR_NO_MORE_AU == err ) { /** * If we (already!) reach the end of the clip, we filter the error. * It will be correctly managed at the first step. */ err = M4NO_ERROR; } else if( M4NO_ERROR != err ) { M4OSA_TRACE1_1("M4VSS3GPP_intOpenClip: \ m_pReaderDataIt->m_pFctGetNextAu() returns 0x%x!", err); return err; } } else { pClipProperties->uiVideoWidth = pClipProperties->uiStillPicWidth; pClipProperties->uiVideoHeight = pClipProperties->uiStillPicHeight; } /* state check not to allocate buffer during save start */ /******************************/ /* Video resize management */ /******************************/ /** * If the input clip is a rotate video or the output resolution is different * from the input resolution, then the video frame needs to be rotated * or resized, force to resize mode */ if (((M4OSA_UInt32)pC->ewc.uiVideoWidth != pClipProperties->uiVideoWidth) || ((M4OSA_UInt32)pC->ewc.uiVideoHeight != pClipProperties->uiVideoHeight) || pClipProperties->videoRotationDegrees != 0) { if (pClip->m_pPreResizeFrame == M4OSA_NULL) { /** * Allocate the intermediate video plane that will receive the decoded image before resizing */ pClip->m_pPreResizeFrame = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc( 3*sizeof(M4VIFI_ImagePlane), M4VSS3GPP, (M4OSA_Char *)"pPreResizeFrame"); if (M4OSA_NULL == pClip->m_pPreResizeFrame) { M4OSA_TRACE1_0("M4MCS_intPrepareVideoEncoder(): \ unable to allocate m_pPreResizeFrame"); return M4ERR_ALLOC; } pClip->m_pPreResizeFrame[0].pac_data = M4OSA_NULL; pClip->m_pPreResizeFrame[1].pac_data = M4OSA_NULL; pClip->m_pPreResizeFrame[2].pac_data = M4OSA_NULL; /** * Allocate the Y plane */ pClip->m_pPreResizeFrame[0].u_topleft = 0; pClip->m_pPreResizeFrame[0].u_width = pClipProperties->uiVideoWidth; pClip->m_pPreResizeFrame[0].u_height = pClipProperties->uiVideoHeight; pClip->m_pPreResizeFrame[0].u_stride = pClip->m_pPreResizeFrame[0].u_width; pClip->m_pPreResizeFrame[0].pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc ( pClip->m_pPreResizeFrame[0].u_stride * pClip->m_pPreResizeFrame[0].u_height, M4MCS, (M4OSA_Char *)"m_pPreResizeFrame[0].pac_data"); if (M4OSA_NULL == pClip->m_pPreResizeFrame[0].pac_data) { M4OSA_TRACE1_0("M4MCS_intPrepareVideoEncoder(): \ unable to allocate m_pPreResizeFrame[0].pac_data"); free(pClip->m_pPreResizeFrame); return M4ERR_ALLOC; } /** * Allocate the U plane */ pClip->m_pPreResizeFrame[1].u_topleft = 0; pClip->m_pPreResizeFrame[1].u_width = pClip->m_pPreResizeFrame[0].u_width >> 1; pClip->m_pPreResizeFrame[1].u_height = pClip->m_pPreResizeFrame[0].u_height >> 1; pClip->m_pPreResizeFrame[1].u_stride = pClip->m_pPreResizeFrame[1].u_width; pClip->m_pPreResizeFrame[1].pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc ( pClip->m_pPreResizeFrame[1].u_stride * pClip->m_pPreResizeFrame[1].u_height, M4MCS, (M4OSA_Char *)"m_pPreResizeFrame[1].pac_data"); if (M4OSA_NULL == pClip->m_pPreResizeFrame[1].pac_data) { M4OSA_TRACE1_0("M4MCS_intPrepareVideoEncoder(): \ unable to allocate m_pPreResizeFrame[1].pac_data"); free(pClip->m_pPreResizeFrame[0].pac_data); free(pClip->m_pPreResizeFrame); return M4ERR_ALLOC; } /** * Allocate the V plane */ pClip->m_pPreResizeFrame[2].u_topleft = 0; pClip->m_pPreResizeFrame[2].u_width = pClip->m_pPreResizeFrame[1].u_width; pClip->m_pPreResizeFrame[2].u_height = pClip->m_pPreResizeFrame[1].u_height; pClip->m_pPreResizeFrame[2].u_stride = pClip->m_pPreResizeFrame[2].u_width; pClip->m_pPreResizeFrame[2].pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc ( pClip->m_pPreResizeFrame[2].u_stride * pClip->m_pPreResizeFrame[2].u_height, M4MCS, (M4OSA_Char *)"m_pPreResizeFrame[2].pac_data"); if (M4OSA_NULL == pClip->m_pPreResizeFrame[2].pac_data) { M4OSA_TRACE1_0("M4MCS_intPrepareVideoEncoder(): \ unable to allocate m_pPreResizeFrame[2].pac_data"); free(pClip->m_pPreResizeFrame[0].pac_data); free(pClip->m_pPreResizeFrame[1].pac_data); free(pClip->m_pPreResizeFrame); return M4ERR_ALLOC; } } } /** * The video is currently in reading mode */ pClip->Vstatus = M4VSS3GPP_kClipStatus_READ; } if( ( M4SYS_kAudioUnknown != pC->ewc.AudioStreamType) && (M4VIDEOEDITING_kMP3 != pClipProperties->AudioStreamType) ) { /** * Read the first Audio AU of the clip */ err = M4VSS3GPP_intClipReadNextAudioFrame(pClip); if( M4OSA_ERR_IS_ERROR(err) ) { M4OSA_TRACE1_1( "M4VSS3GPP_intOpenClip: M4VSS3GPP_intClipReadNextAudioFrame returns 0x%x!", err); return err; } /** * The audio is currently in reading mode */ pClip->Astatus = M4VSS3GPP_kClipStatus_READ; } /** * Return with no error */ M4OSA_TRACE3_0("M4VSS3GPP_intOpenClip(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_intComputeOutputAverageVideoBitrate() * @brief Average bitrate of the output file, computed from input bitrates, * durations, transitions and cuts. * @param pC (IN/OUT) Internal edit context ****************************************************************************** */ static M4OSA_Void M4VSS3GPP_intComputeOutputAverageVideoBitrate( M4VSS3GPP_InternalEditContext *pC ) { M4VSS3GPP_ClipSettings *pCS_0, *pCS_1, *pCS_2; M4VSS3GPP_TransitionSettings *pT0, *pT2; M4OSA_Int32 i; M4OSA_UInt32 t0_duration, t2_duration; M4OSA_UInt32 t0_bitrate, t2_bitrate; M4OSA_UInt32 c1_duration; M4OSA_UInt32 total_duration; M4OSA_UInt32 total_bitsum; total_duration = 0; total_bitsum = 0; /* Loop on the number of clips */ for ( i = 0; i < pC->uiClipNumber; i++ ) { pCS_1 = &pC->pClipList[i]; t0_duration = 0; t0_bitrate = pCS_1->ClipProperties.uiVideoBitrate; t2_duration = 0; t2_bitrate = pCS_1->ClipProperties.uiVideoBitrate; /* Transition with the previous clip */ if( i > 0 ) { pCS_0 = &pC->pClipList[i - 1]; pT0 = &pC->pTransitionList[i - 1]; if( pT0->VideoTransitionType != M4VSS3GPP_kVideoTransitionType_None ) { t0_duration = pT0->uiTransitionDuration; if( pCS_0->ClipProperties.uiVideoBitrate > t0_bitrate ) { t0_bitrate = pCS_0->ClipProperties.uiVideoBitrate; } } } /* Transition with the next clip */ if( i < pC->uiClipNumber - 1 ) { pCS_2 = &pC->pClipList[i + 1]; pT2 = &pC->pTransitionList[i]; if( pT2->VideoTransitionType != M4VSS3GPP_kVideoTransitionType_None ) { t2_duration = pT2->uiTransitionDuration; if( pCS_2->ClipProperties.uiVideoBitrate > t2_bitrate ) { t2_bitrate = pCS_2->ClipProperties.uiVideoBitrate; } } } /* Check for cut times */ if( pCS_1->uiEndCutTime > 0 ) c1_duration = pCS_1->uiEndCutTime; else c1_duration = pCS_1->ClipProperties.uiClipVideoDuration; if( pCS_1->uiBeginCutTime > 0 ) c1_duration -= pCS_1->uiBeginCutTime; c1_duration -= t0_duration + t2_duration; /* Compute bitsum and duration */ total_duration += c1_duration + t0_duration / 2 + t2_duration / 2; total_bitsum += c1_duration * (pCS_1->ClipProperties.uiVideoBitrate / 1000) + (t0_bitrate / 1000) * t0_duration / 2 + (t2_bitrate / 1000) * t2_duration / 2; } pC->ewc.uiVideoBitrate = ( total_bitsum / total_duration) * 1000; }