| /* |
| * 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; |
| } |
| |