diff options
Diffstat (limited to 'libvideoeditor/vss/src/M4VSS3GPP_EditAudio.c')
-rwxr-xr-x | libvideoeditor/vss/src/M4VSS3GPP_EditAudio.c | 2013 |
1 files changed, 0 insertions, 2013 deletions
diff --git a/libvideoeditor/vss/src/M4VSS3GPP_EditAudio.c b/libvideoeditor/vss/src/M4VSS3GPP_EditAudio.c deleted file mode 100755 index 746883d..0000000 --- a/libvideoeditor/vss/src/M4VSS3GPP_EditAudio.c +++ /dev/null @@ -1,2013 +0,0 @@ -/* - * 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_EditAudio.c - * @brief Video Studio Service 3GPP edit API implementation. - * @note - ****************************************************************************** - */ - -/****************/ -/*** Includes ***/ -/****************/ - -#include "NXPSW_CompilerSwitches.h" -/** - * Our header */ -#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 */ - -#define PWR_FXP_FRACT_MAX (32768) - -/************************************************************************/ -/* Static local functions */ -/************************************************************************/ -static M4OSA_ERR M4VSS3GPP_intCheckAudioMode( M4VSS3GPP_InternalEditContext - *pC ); -static M4OSA_Void M4VSS3GPP_intCheckAudioEffects( M4VSS3GPP_InternalEditContext - *pC, M4OSA_UInt8 uiClipNumber ); -static M4OSA_ERR M4VSS3GPP_intApplyAudioEffect( M4VSS3GPP_InternalEditContext - *pC, M4OSA_UInt8 uiClip1orClip2, - M4OSA_Int16 *pPCMdata, - M4OSA_UInt32 uiPCMsize ); -static M4OSA_ERR M4VSS3GPP_intAudioTransition( M4VSS3GPP_InternalEditContext - *pC, M4OSA_Int16 *pPCMdata1, - M4OSA_Int16 *pPCMdata2, - M4OSA_UInt32 uiPCMsize ); - -/** - ****************************************************************************** - * M4OSA_ERR M4VSS3GPP_intEditJumpMP3() - * @brief One step of jumping processing for the MP3 clip. - * @note On one step, the jump of several AU is done - * @param pC (IN/OUT) Internal edit context - ****************************************************************************** - */ -M4OSA_ERR M4VSS3GPP_intEditJumpMP3( M4VSS3GPP_InternalEditContext *pC ) -{ - M4OSA_ERR err; - M4VSS3GPP_ClipContext *pClip = pC->pC1; /**< shortcut */ - M4OSA_Int32 JumpCts; - - JumpCts = pClip->iActualAudioBeginCut; - - err = M4VSS3GPP_intClipJumpAudioAt(pClip, &JumpCts); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intOpenClip: M4VSS3GPP_intClipJumpAudioAt(A) returns 0x%x!", - err); - return err; - } - - if( JumpCts >= pClip->iActualAudioBeginCut ) - { - pC->State = M4VSS3GPP_kEditState_MP3; - - /** - * Update clip offset with the audio begin cut */ - pClip->iAoffset = -JumpCts; - - /** - * The audio is currently in reading mode */ - pClip->Astatus = M4VSS3GPP_kClipStatus_READ; - } - return M4NO_ERROR; -} - -/** - ****************************************************************************** - * M4OSA_ERR M4VSS3GPP_intEditStepMP3() - * @brief One step of audio processing for the MP3 clip - * @param pC (IN/OUT) Internal edit context - ****************************************************************************** - */ -M4OSA_ERR M4VSS3GPP_intEditStepMP3( M4VSS3GPP_InternalEditContext *pC ) -{ - M4OSA_ERR err; - M4VSS3GPP_ClipContext *pClip = pC->pC1; /**< shortcut */ - - /** - * Copy the input AU to the output AU */ - err = pC->pOsaFileWritPtr->writeData(pC->ewc.p3gpWriterContext, - pClip->pAudioFramePtr, (M4OSA_UInt32)pClip->uiAudioFrameSize); - - /** - * Read the next audio frame */ - err = M4VSS3GPP_intClipReadNextAudioFrame(pClip); - - if( M4OSA_ERR_IS_ERROR(err) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepMP3: READ_WRITE:\ - M4VSS3GPP_intClipReadNextAudioFrame returns 0x%x!", err); - return err; - } - else - { - /** - * Update current time (to=tc+T) */ - pC->ewc.dATo = - ( pClip->iAudioFrameCts + pClip->iAoffset) / pClip->scale_audio; - - if( (M4OSA_Int32)(pClip->iAudioFrameCts / pClip->scale_audio + 0.5) - >= pClip->iEndTime ) - { - M4READER_Buffer mp3tagBuffer; - - /** - * The duration is better respected if the first AU and last AU are both above - the cut time */ - err = pC->pOsaFileWritPtr->writeData(pC->ewc.p3gpWriterContext, - pClip->pAudioFramePtr, - (M4OSA_UInt32)pClip->uiAudioFrameSize); - - /* The ID3v1 tag is always at the end of the mp3 file so the end of the cutting - process is waited */ - /* before writing the metadata in the output file*/ - - /* Retrieve the data of the ID3v1 Tag */ - err = pClip->ShellAPI.m_pReader->m_pFctGetOption( - pClip->pReaderContext, M4READER_kOptionID_Mp3Id3v1Tag, - (M4OSA_DataOption) &mp3tagBuffer); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepMP3: M4MP3R_getOption returns 0x%x", - err); - return err; - } - - /* Write the data of the ID3v1 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_intEditStepMP3:\ - pOsaFileWritPtr->writeData(ID3v1Tag) returns 0x%x", err); - return err; - } - - mp3tagBuffer.m_uiBufferSize = 0; - mp3tagBuffer.m_pData = M4OSA_NULL; - } - - /* The End Cut has been reached */ - err = M4VSS3GPP_intReachedEndOfAudio(pC); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepMP3 : M4VSS3GPP_intReachedEndOfAudio returns 0x%x", - err); - return err; - } - } - - if( ( M4WAR_NO_MORE_AU == err) && (M4OSA_FALSE - == pC->bSupportSilence) ) /**< Reached end of clip */ - { - err = M4VSS3GPP_intReachedEndOfAudio( - pC); /**< Clip done, do the next one */ - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepMP3: READ_WRITE:\ - M4VSS3GPP_intReachedEndOfAudio returns 0x%x", - err); - return err; - } - } - } - - /** - * Return with no error */ - M4OSA_TRACE3_0("M4VSS3GPP_intEditStepMP3: returning M4NO_ERROR"); - return M4NO_ERROR; -} -/** - ****************************************************************************** - * M4OSA_ERR M4VSS3GPP_intEditStepAudio() - * @brief One step of audio processing - * @param pC (IN/OUT) Internal edit context - ****************************************************************************** - */ -M4OSA_ERR M4VSS3GPP_intEditStepAudio( M4VSS3GPP_InternalEditContext *pC ) -{ - M4OSA_ERR err; - int32_t auTimeStamp = -1; - - M4ENCODER_AudioBuffer pEncInBuffer; /**< Encoder input buffer for api */ - M4ENCODER_AudioBuffer pEncOutBuffer; /**< Encoder output buffer for api */ - M4OSA_Time - frameTimeDelta; /**< Duration of the encoded (then written) data */ - M4OSA_Bool bStopAudio; - - /** - * Check if we reached end cut */ - if( ( pC->ewc.dATo - pC->pC1->iAoffset / pC->pC1->scale_audio + 0.5) - >= pC->pC1->iEndTime ) - { - /** - * Audio is done for this clip */ - err = M4VSS3GPP_intReachedEndOfAudio(pC); - - /* RC: to know when a file has been processed */ - if( M4NO_ERROR != err && err != M4VSS3GPP_WAR_SWITCH_CLIP ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: M4VSS3GPP_intReachedEndOfAudio returns 0x%x", - err); - } - - return err; - } - - /** - * Check Audio Mode, depending on the current output CTS */ - err = M4VSS3GPP_intCheckAudioMode( - pC); /**< This function change the pC->Astate variable! */ - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: M4VSS3GPP_intCheckAudioMode returns 0x%x!", - err); - return err; - } - - M4OSA_TRACE2_3(" AUDIO step : dATo = %f state = %d offset = %ld", - pC->ewc.dATo, pC->Astate, pC->pC1->iAoffset); - - bStopAudio = M4OSA_FALSE; - - switch( pC->Astate ) - { - /* _________________ */ - /*| |*/ - /*| READ_WRITE MODE |*/ - /*|_________________|*/ - - case M4VSS3GPP_kEditAudioState_READ_WRITE: - { - M4OSA_TRACE3_0("M4VSS3GPP_intEditStepAudio READ_WRITE"); - - /** - * Get the output AU to write into */ - err = pC->ShellAPI.pWriterDataFcts->pStartAU( - pC->ewc.p3gpWriterContext, M4VSS3GPP_WRITER_AUDIO_STREAM_ID, - &pC->ewc.WriterAudioAU); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio:\ - READ_WRITE: pWriterDataFcts->pStartAU returns 0x%x!", - err); - return err; - } - - /** - * Compute output audio CTS */ - pC->ewc.WriterAudioAU.CTS = - pC->pC1->iAudioFrameCts + pC->pC1->iAoffset; - - /** - * BZZZ bug fix (read-write case): - * Replace the first AMR AU of the stream with a silence AU. - * It removes annoying "BZZZ" audio glitch. - * It is not needed if there is a begin cut. - * It is not needed for the first clip. - * Because of another bugfix (2005-03-24), the first AU written may be - * the second one which CTS is 20. Hence the cts<21 test. - * (the BZZZ effect occurs even with the second AU!) */ - if( ( M4OSA_FALSE == pC->pC1->bFirstAuWritten) - && (0 != pC->uiCurrentClip) && (pC->pC1->iAudioFrameCts - < (pC->ewc.iSilenceFrameDuration + 1)) ) - { - /** - * Copy a silence AU to the output */ - pC->ewc.WriterAudioAU.size = pC->ewc.uiSilenceFrameSize; - memcpy((void *)pC->ewc.WriterAudioAU.dataAddress, - (void *)pC->ewc.pSilenceFrameData, pC->ewc.uiSilenceFrameSize); - M4OSA_TRACE2_0("A #### silence AU"); - } - else if( (M4OSA_UInt32)pC->pC1->uiAudioFrameSize - < pC->ewc.uiAudioMaxAuSize ) - { - /** - * Copy the input AU to the output AU */ - pC->ewc.WriterAudioAU.size = - (M4OSA_UInt32)pC->pC1->uiAudioFrameSize; - memcpy((void *)pC->ewc.WriterAudioAU.dataAddress, - (void *)pC->pC1->pAudioFramePtr, pC->ewc.WriterAudioAU.size); - } - else - { - M4OSA_TRACE1_2( - "M4VSS3GPP_intEditStepAudio: READ_WRITE: AU size greater than MaxAuSize \ - (%d>%d)! returning M4VSS3GPP_ERR_INPUT_AUDIO_AU_TOO_LARGE", - pC->pC1->uiAudioFrameSize, pC->ewc.uiAudioMaxAuSize); - return M4VSS3GPP_ERR_INPUT_AUDIO_AU_TOO_LARGE; - } - - /** - * This boolean is only used to fix the BZZ bug... */ - pC->pC1->bFirstAuWritten = M4OSA_TRUE; - - M4OSA_TRACE2_2("B ---- write : cts = %ld [ 0x%x ]", - (M4OSA_Int32)(pC->ewc.WriterAudioAU.CTS / pC->ewc.scale_audio), - pC->ewc.WriterAudioAU.size); - - /** - * Write the AU */ - err = pC->ShellAPI.pWriterDataFcts->pProcessAU( - pC->ewc.p3gpWriterContext, M4VSS3GPP_WRITER_AUDIO_STREAM_ID, - &pC->ewc.WriterAudioAU); - - if( M4NO_ERROR != err ) - { - /*11/12/2008 CR 3283 MMS use case for VideoArtist - the warning M4WAR_WRITER_STOP_REQ is returned when the targeted output file - size is reached - The editing is then finished, - the warning M4VSS3GPP_WAR_EDITING_DONE is returned*/ - if( M4WAR_WRITER_STOP_REQ == err ) - { - M4OSA_TRACE1_0( - "M4VSS3GPP_intEditStepAudio: File was cut to avoid oversize"); - return M4VSS3GPP_WAR_EDITING_DONE; - } - else - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio:\ - READ_WRITE: pWriterDataFcts->pProcessAU returns 0x%x!", - err); - return err; - } - } - - /** - * Audio is now in read mode (there may be a "if(status!=READ)" here, - but it is removed for optimization) */ - pC->pC1->Astatus = M4VSS3GPP_kClipStatus_READ; - - /** - * Read the next audio frame */ - err = M4VSS3GPP_intClipReadNextAudioFrame(pC->pC1); - - M4OSA_TRACE2_3("C .... read : cts = %.0f + %.0f [ 0x%x ]", - pC->pC1->iAudioFrameCts / pC->pC1->scale_audio, - pC->pC1->iAoffset / pC->pC1->scale_audio, - pC->pC1->uiAudioFrameSize); - - if( M4OSA_ERR_IS_ERROR(err) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: READ_WRITE:\ - M4VSS3GPP_intClipReadNextAudioFrame returns 0x%x!", - err); - return err; - } - else - { - /** - * Update current time (to=tc+T) */ - pC->ewc.dATo = ( pC->pC1->iAudioFrameCts + pC->pC1->iAoffset) - / pC->pC1->scale_audio; - - if( ( M4WAR_NO_MORE_AU == err) - && (M4OSA_FALSE == pC->bSupportSilence) ) - { - /** - * If output is other than AMR or AAC - (i.e. EVRC,we can't write silence into it) - * So we simply end here.*/ - bStopAudio = M4OSA_TRUE; - } - } - } - break; - - /* ____________________ */ - /*| |*/ - /*| DECODE_ENCODE MODE |*/ - /*|____________________|*/ - - case M4VSS3GPP_kEditAudioState_DECODE_ENCODE: - { - M4OSA_TRACE3_0("M4VSS3GPP_intEditStepAudio DECODE_ENCODE"); - - /** - * Get the output AU to write into */ - err = pC->ShellAPI.pWriterDataFcts->pStartAU( - pC->ewc.p3gpWriterContext, M4VSS3GPP_WRITER_AUDIO_STREAM_ID, - &pC->ewc.WriterAudioAU); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: DECODE_ENCODE:\ - pWriterDataFcts->pStartAU returns 0x%x!", - err); - return err; - } - - /** - * If we were reading the clip, we must jump a few AU backward to decode/encode - (without writing result) from that point. */ - if( M4VSS3GPP_kClipStatus_READ == pC->pC1->Astatus ) - { - M4OSA_Int32 iTargetCts, iCurrentCts; - - if( 0 - != pC->pC1-> - iAudioFrameCts ) /**<don't try to pre-decode if clip is at its beginning. */ - { - /** - * Jump a few AUs backward */ - iCurrentCts = pC->pC1->iAudioFrameCts; - iTargetCts = iCurrentCts - M4VSS3GPP_NB_AU_PREFETCH - * pC->ewc.iSilenceFrameDuration; - - if( iTargetCts < 0 ) - { - iTargetCts = 0; /**< Sanity check */ - } - - err = M4VSS3GPP_intClipJumpAudioAt(pC->pC1, &iTargetCts); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: DECODE_ENCODE-prefetch:\ - M4VSS3GPP_intClipJumpAudioAt returns 0x%x!", - err); - return err; - } - - err = M4VSS3GPP_intClipReadNextAudioFrame( - pC->pC1); /**< read AU where we jumped */ - - M4OSA_TRACE2_3("D .... read : cts = %.0f + %.0f [ 0x%x ]", - pC->pC1->iAudioFrameCts / pC->pC1->scale_audio, - pC->pC1->iAoffset / pC->pC1->scale_audio, - pC->pC1->uiAudioFrameSize); - - if( M4OSA_ERR_IS_ERROR(err) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: DECODE_ENCODE-prefetch:\ - M4VSS3GPP_intClipReadNextAudioFrame(a) returns 0x%x!", - err); - return err; - } - - /** - * Decode/encode up to the wanted position */ - while( pC->pC1->iAudioFrameCts < iCurrentCts ) - { - err = M4VSS3GPP_intClipDecodeCurrentAudioFrame(pC->pC1); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: DECODE_ENCODE-prefetch: \ - M4VSS3GPP_intClipDecodeCurrentAudioFrame returns 0x%x!", - err); - return err; - } - - /* [Mono] or [Stereo interleaved] : all is in one buffer */ - pEncInBuffer.pTableBuffer[0] = - pC->pC1->AudioDecBufferOut.m_dataAddress; - pEncInBuffer.pTableBufferSize[0] = - pC->pC1->AudioDecBufferOut.m_bufferSize; - pEncInBuffer.pTableBuffer[1] = M4OSA_NULL; - pEncInBuffer.pTableBufferSize[1] = 0; - - /* Time in ms from data size, because it is PCM16 samples */ - frameTimeDelta = - pEncInBuffer.pTableBufferSize[0] / sizeof(short) - / pC->ewc.uiNbChannels; - - /** - * Prepare output buffer */ - pEncOutBuffer.pTableBuffer[0] = - (M4OSA_MemAddr8)pC->ewc.WriterAudioAU.dataAddress; - pEncOutBuffer.pTableBufferSize[0] = 0; - - M4OSA_TRACE2_0("E **** pre-encode"); -#ifdef M4VSS_SUPPORT_OMX_CODECS - /*OMX Audio decoder used. - * OMX Audio dec shell does internal buffering and hence does not return - a PCM buffer for every decodeStep call.* - * So PCM buffer sizes might be 0. In this case donot call encode Step*/ - - if( 0 != pEncInBuffer.pTableBufferSize[0] ) - { -#endif - /** - * Encode the PCM audio */ - - err = - pC->ShellAPI.pAudioEncoderGlobalFcts->pFctStep( - pC->ewc.pAudioEncCtxt, - &pEncInBuffer, &pEncOutBuffer); - - if( ( M4NO_ERROR != err) - && (M4WAR_NO_MORE_AU != err) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio():\ - pAudioEncoderGlobalFcts->pFctStep returns 0x%x", - err); - return err; - } -#ifdef M4VSS_SUPPORT_OMX_CODECS - - } //if(0 != pEncInBuffer.pTableBufferSize[0]) - -#endif - pC->pC1->pAudioFramePtr = M4OSA_NULL; - - // Get timestamp of last read AU - pC->pC1->ShellAPI.m_pAudioDecoder->m_pFctGetOptionAudioDec( - pC->pC1->pAudioDecCtxt, M4AD_kOptionID_AuCTS, - (M4OSA_DataOption) &auTimeStamp); - - if (auTimeStamp == -1) { - M4OSA_TRACE1_0("M4VSS3GPP_intEditStepAudio: \ - invalid audio timestamp returned"); - return M4WAR_INVALID_TIME; - } - - pC->pC1->iAudioFrameCts = auTimeStamp; - - } - } - - /** - * Audio is now OK for decoding */ - pC->pC1->Astatus = M4VSS3GPP_kClipStatus_DECODE; - } - - /** - * Decode the input audio */ - err = M4VSS3GPP_intClipDecodeCurrentAudioFrame(pC->pC1); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: DECODE_ENCODE:\ - M4VSS3GPP_intClipDecodeCurrentAudioFrame returns 0x%x", - err); - return err; - } - - pC->pC1->pAudioFramePtr = M4OSA_NULL; - - // Get timestamp of last read AU - pC->pC1->ShellAPI.m_pAudioDecoder->m_pFctGetOptionAudioDec( - pC->pC1->pAudioDecCtxt, M4AD_kOptionID_AuCTS, - (M4OSA_DataOption) &auTimeStamp); - - if (auTimeStamp == -1) { - M4OSA_TRACE1_0("M4VSS3GPP_intEditStepAudio: invalid audio \ - timestamp returned"); - return M4WAR_INVALID_TIME; - } - - pC->pC1->iAudioFrameCts = auTimeStamp; - - /** - * Apply the effect */ - if( pC->iClip1ActiveEffect >= 0 ) - { - err = M4VSS3GPP_intApplyAudioEffect(pC, 1, (M4OSA_Int16 - *)pC->pC1->AudioDecBufferOut.m_dataAddress, - pC->pC1->AudioDecBufferOut.m_bufferSize); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: DECODE_ENCODE:\ - M4VSS3GPP_intEndAudioEffect returns 0x%x", - err); - return err; - } - } - - /** - * Compute output audio CTS */ - pC->ewc.WriterAudioAU.CTS = - pC->pC1->iAudioFrameCts + pC->pC1->iAoffset; - - /* May happen with corrupted input files (which have stts entries not - multiple of SilenceFrameDuration) */ - if( pC->ewc.WriterAudioAU.CTS < 0 ) - { - pC->ewc.WriterAudioAU.CTS = 0; - } - - /** - * BZZZ bug fix (decode-encode case): - * (Yes, the Bzz bug may also occur when we re-encode. It doesn't - * occur at the decode before the encode, but at the playback!) - * Replace the first AMR AU of the encoded stream with a silence AU. - * It removes annoying "BZZZ" audio glitch. - * It is not needed if there is a begin cut. - * It is not needed for the first clip. - * Because of another bugfix (2005-03-24), the first AU written may be - * the second one which CTS is 20. Hence the cts<21 test. - * (the BZZZ effect occurs even with the second AU!) */ - if( ( M4OSA_FALSE == pC->pC1->bFirstAuWritten) - && (0 != pC->uiCurrentClip) && (pC->pC1->iAudioFrameCts - < (pC->ewc.iSilenceFrameDuration + 1)) ) - { - /** - * Copy a silence AMR AU to the output */ - pC->ewc.WriterAudioAU.size = pC->ewc.uiSilenceFrameSize; - memcpy((void *)pC->ewc.WriterAudioAU.dataAddress, - (void *)pC->ewc.pSilenceFrameData, pC->ewc.uiSilenceFrameSize); - M4OSA_TRACE2_0("G #### silence AU"); - } - else - { - /** - * Encode the filtered PCM audio directly into the output AU */ - - /* [Mono] or [Stereo interleaved] : all is in one buffer */ - pEncInBuffer.pTableBuffer[0] = - pC->pC1->AudioDecBufferOut.m_dataAddress; - pEncInBuffer.pTableBufferSize[0] = - pC->pC1->AudioDecBufferOut.m_bufferSize; - pEncInBuffer.pTableBuffer[1] = M4OSA_NULL; - pEncInBuffer.pTableBufferSize[1] = 0; - - /* Time in ms from data size, because it is PCM16 samples */ - frameTimeDelta = - pEncInBuffer.pTableBufferSize[0] / sizeof(short) - / pC->ewc.uiNbChannels; - - /** - * Prepare output buffer */ - pEncOutBuffer.pTableBuffer[0] = - (M4OSA_MemAddr8)pC->ewc.WriterAudioAU.dataAddress; - pEncOutBuffer.pTableBufferSize[0] = 0; - - M4OSA_TRACE2_0("H ++++ encode AU"); - -#ifdef M4VSS_SUPPORT_OMX_CODECS - /*OMX Audio decoder used. - * OMX Audio dec shell does internal buffering and hence does not return - a PCM buffer for every decodeStep call.* - * So PCM buffer sizes might be 0. In this case donot call encode Step*/ - - if( 0 != pEncInBuffer.pTableBufferSize[0] ) - { - -#endif - - /** - * Encode the PCM audio */ - - err = pC->ShellAPI.pAudioEncoderGlobalFcts->pFctStep( - pC->ewc.pAudioEncCtxt, - &pEncInBuffer, &pEncOutBuffer); - - if( ( M4NO_ERROR != err) && (M4WAR_NO_MORE_AU != err) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio():\ - pAudioEncoderGlobalFcts->pFctStep returns 0x%x", - err); - return err; - } -#ifdef M4VSS_SUPPORT_OMX_CODECS - - } - -#endif - - /** - * Set AU size */ - - pC->ewc.WriterAudioAU.size = pEncOutBuffer.pTableBufferSize[ - 0]; /**< Get the size of encoded data */ - } - - /** - * This boolean is only used to fix the BZZ bug... */ - pC->pC1->bFirstAuWritten = M4OSA_TRUE; - - M4OSA_TRACE2_2("I ---- write : cts = %ld [ 0x%x ]", - (M4OSA_Int32)(pC->ewc.WriterAudioAU.CTS / pC->ewc.scale_audio), - pC->ewc.WriterAudioAU.size); - - /** - * Write the AU */ - err = pC->ShellAPI.pWriterDataFcts->pProcessAU( - pC->ewc.p3gpWriterContext, M4VSS3GPP_WRITER_AUDIO_STREAM_ID, - &pC->ewc.WriterAudioAU); - - if( M4NO_ERROR != err ) - { - /*11/12/2008 CR 3283 MMS use case for VideoArtist - the warning M4WAR_WRITER_STOP_REQ is returned when the targeted output file - size is reached - The editing is then finished, - the warning M4VSS3GPP_WAR_EDITING_DONE is returned*/ - if( M4WAR_WRITER_STOP_REQ == err ) - { - M4OSA_TRACE1_0( - "M4VSS3GPP_intEditStepAudio: File was cut to avoid oversize"); - return M4VSS3GPP_WAR_EDITING_DONE; - } - else - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: DECODE_ENCODE:\ - pWriterDataFcts->pProcessAU returns 0x%x!", - err); - return err; - } - } - - /** - * Read the next audio frame */ - err = M4VSS3GPP_intClipReadNextAudioFrame(pC->pC1); - - M4OSA_TRACE2_3("J .... read : cts = %.0f + %.0f [ 0x%x ]", - pC->pC1->iAudioFrameCts / pC->pC1->scale_audio, - pC->pC1->iAoffset / pC->pC1->scale_audio, - pC->pC1->uiAudioFrameSize); - - if( M4OSA_ERR_IS_ERROR(err) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: DECODE_ENCODE:\ - M4VSS3GPP_intClipReadNextAudioFrame returns 0x%x!", - err); - return err; - } - else - { - /** - * Update current time (to=tc+T) */ - pC->ewc.dATo = ( pC->pC1->iAudioFrameCts + pC->pC1->iAoffset) - / pC->pC1->scale_audio; - - if( ( M4WAR_NO_MORE_AU == err) - && (M4OSA_FALSE == pC->bSupportSilence) ) - { - /** - * If output is other than AMR or AAC - (i.e. EVRC,we can't write silence into it) - * So we simply end here.*/ - bStopAudio = M4OSA_TRUE; - } - } - } - break; - - /* _________________ */ - /*| |*/ - /*| TRANSITION MODE |*/ - /*|_________________|*/ - - case M4VSS3GPP_kEditAudioState_TRANSITION: - { - M4OSA_TRACE3_0("M4VSS3GPP_intEditStepAudio TRANSITION"); - - /** - * Get the output AU to write into */ - err = pC->ShellAPI.pWriterDataFcts->pStartAU( - pC->ewc.p3gpWriterContext, M4VSS3GPP_WRITER_AUDIO_STREAM_ID, - &pC->ewc.WriterAudioAU); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION:\ - pWriterDataFcts->pStartAU returns 0x%x!", - err); - return err; - } - - /** - * If we were reading the clip, we must jump a few AU backward to decode/encode - (without writing result) from that point. */ - if( M4VSS3GPP_kClipStatus_READ == pC->pC1->Astatus ) - { - M4OSA_Int32 iTargetCts, iCurrentCts; - - if( 0 - != pC->pC1-> - iAudioFrameCts ) /**<don't try to pre-decode if clip is at its beginning.*/ - { - /** - * Jump a few AUs backward */ - iCurrentCts = pC->pC1->iAudioFrameCts; - iTargetCts = iCurrentCts - M4VSS3GPP_NB_AU_PREFETCH - * pC->ewc.iSilenceFrameDuration; - - if( iTargetCts < 0 ) - { - iTargetCts = 0; /**< Sanity check */ - } - - err = M4VSS3GPP_intClipJumpAudioAt(pC->pC1, &iTargetCts); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION-prefetch:\ - M4VSS3GPP_intClipJumpAudioAt returns 0x%x!", - err); - return err; - } - - err = M4VSS3GPP_intClipReadNextAudioFrame( - pC->pC1); /**< read AU where we jumped */ - - M4OSA_TRACE2_3("K .... read : cts = %.0f + %.0f [ 0x%x ]", - pC->pC1->iAudioFrameCts / pC->pC1->scale_audio, - pC->pC1->iAoffset / pC->pC1->scale_audio, - pC->pC1->uiAudioFrameSize); - - if( M4OSA_ERR_IS_ERROR(err) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION-prefetch:\ - M4VSS3GPP_intClipReadNextAudioFrame(a) returns 0x%x!", - err); - return err; - } - - /** - * Decode/encode up to the wanted position */ - while( pC->pC1->iAudioFrameCts < iCurrentCts ) - { - err = M4VSS3GPP_intClipDecodeCurrentAudioFrame(pC->pC1); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION-prefetch:\ - M4VSS3GPP_intClipDecodeCurrentAudioFrame returns 0x%x!", - err); - return err; - } - - /* [Mono] or [Stereo interleaved] : all is in one buffer */ - pEncInBuffer.pTableBuffer[0] = - pC->pC1->AudioDecBufferOut.m_dataAddress; - pEncInBuffer.pTableBufferSize[0] = - pC->pC1->AudioDecBufferOut.m_bufferSize; - pEncInBuffer.pTableBuffer[1] = M4OSA_NULL; - pEncInBuffer.pTableBufferSize[1] = 0; - - /* Time in ms from data size, because it is PCM16 samples */ - frameTimeDelta = - pEncInBuffer.pTableBufferSize[0] / sizeof(short) - / pC->ewc.uiNbChannels; - - /** - * Prepare output buffer */ - pEncOutBuffer.pTableBuffer[0] = - (M4OSA_MemAddr8)pC->ewc.WriterAudioAU.dataAddress; - pEncOutBuffer.pTableBufferSize[0] = 0; - - M4OSA_TRACE2_0("L **** pre-encode"); -#ifdef M4VSS_SUPPORT_OMX_CODECS - /*OMX Audio decoder used. - * OMX Audio dec shell does internal buffering and hence does not return - a PCM buffer for every decodeStep call.* - * So PCM buffer sizes might be 0. In this case donot call encode Step*/ - - if( 0 != pEncInBuffer.pTableBufferSize[0] ) - { - -#endif - /** - * Encode the PCM audio */ - - err = - pC->ShellAPI.pAudioEncoderGlobalFcts->pFctStep( - pC->ewc.pAudioEncCtxt, - &pEncInBuffer, &pEncOutBuffer); - - if( ( M4NO_ERROR != err) - && (M4WAR_NO_MORE_AU != err) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio():\ - pAudioEncoderGlobalFcts->pFctStep returns 0x%x", - err); - return err; - } -#ifdef M4VSS_SUPPORT_OMX_CODECS - - } - -#endif - - err = M4VSS3GPP_intClipReadNextAudioFrame(pC->pC1); - - M4OSA_TRACE2_3( - "M .... read : cts = %.0f + %.0f [ 0x%x ]", - pC->pC1->iAudioFrameCts / pC->pC1->scale_audio, - pC->pC1->iAoffset / pC->pC1->scale_audio, - pC->pC1->uiAudioFrameSize); - - if( M4OSA_ERR_IS_ERROR(err) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION-prefetch:\ - M4VSS3GPP_intClipReadNextAudioFrame(b) returns 0x%x!", - err); - return err; - } - } - } - - /** - * Audio is now OK for decoding */ - pC->pC1->Astatus = M4VSS3GPP_kClipStatus_DECODE; - } - - /** - * Decode the first input audio */ - err = M4VSS3GPP_intClipDecodeCurrentAudioFrame(pC->pC1); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION:\ - M4VSS3GPP_intClipDecodeCurrentAudioFrame(C1) returns 0x%x", - err); - return err; - } - - /** - * Decode the second input audio */ - err = M4VSS3GPP_intClipDecodeCurrentAudioFrame(pC->pC2); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION:\ - M4VSS3GPP_intClipDecodeCurrentAudioFrame(C2) returns 0x%x", - err); - return err; - } - - /** - * Check both clips decoded the same amount of PCM samples */ - if( pC->pC1->AudioDecBufferOut.m_bufferSize - != pC->pC2->AudioDecBufferOut.m_bufferSize ) - { - M4OSA_TRACE1_2( - "ERR : AudioTransition: both clips AU must have the same decoded\ - PCM size! pc1 size=0x%x, pC2 size = 0x%x", - pC->pC1->AudioDecBufferOut.m_bufferSize, - pC->pC2->AudioDecBufferOut.m_bufferSize); -#ifdef M4VSS_SUPPORT_OMX_CODECS - /*OMX Audio decoder used. - * OMX Audio dec shell does internal buffering and hence does not return - a PCM buffer for every decodeStep call.* - * So PCM buffer sizes might be 0 or different for clip1 and clip2. - * So no need to return error in this case */ - - M4OSA_TRACE1_2( - "M4VSS3GPP_intEditStepAudio: , pc1 AudBuff size=0x%x,\ - pC2 AudBuff size = 0x%x", - pC->pC1->AudioDecBufferOut.m_bufferSize, - pC->pC2->AudioDecBufferOut.m_bufferSize); - -#else - - return M4VSS3GPP_ERR_AUDIO_DECODED_PCM_SIZE_ISSUE; - -#endif // M4VSS_SUPPORT_OMX_CODECS - - } - - /** - * Apply the audio effect on clip1 */ - if( pC->iClip1ActiveEffect >= 0 ) - { - err = M4VSS3GPP_intApplyAudioEffect(pC, 1, (M4OSA_Int16 - *)pC->pC1->AudioDecBufferOut.m_dataAddress, - pC->pC1->AudioDecBufferOut.m_bufferSize); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION:\ - M4VSS3GPP_intApplyAudioEffect(C1) returns 0x%x", - err); - return err; - } - } - - /** - * Apply the audio effect on clip2 */ - if( pC->iClip2ActiveEffect >= 0 ) - { - err = M4VSS3GPP_intApplyAudioEffect(pC, 2, (M4OSA_Int16 - *)pC->pC2->AudioDecBufferOut.m_dataAddress, - pC->pC2->AudioDecBufferOut.m_bufferSize); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION:\ - M4VSS3GPP_intApplyAudioEffect(C2) returns 0x%x", - err); - return err; - } - } - - /** - * Apply the transition effect */ - err = M4VSS3GPP_intAudioTransition(pC, - (M4OSA_Int16 *)pC->pC1->AudioDecBufferOut.m_dataAddress, - (M4OSA_Int16 *)pC->pC2->AudioDecBufferOut.m_dataAddress, - pC->pC1->AudioDecBufferOut.m_bufferSize); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION:\ - M4VSS3GPP_intAudioTransition returns 0x%x", - err); - return err; - } - - /* [Mono] or [Stereo interleaved] : all is in one buffer */ - pEncInBuffer.pTableBuffer[0] = - pC->pC1->AudioDecBufferOut.m_dataAddress; - pEncInBuffer.pTableBufferSize[0] = - pC->pC1->AudioDecBufferOut.m_bufferSize; - pEncInBuffer.pTableBuffer[1] = M4OSA_NULL; - pEncInBuffer.pTableBufferSize[1] = 0; - - /* Time in ms from data size, because it is PCM16 samples */ - frameTimeDelta = pEncInBuffer.pTableBufferSize[0] / sizeof(short) - / pC->ewc.uiNbChannels; - - /** - * Prepare output buffer */ - pEncOutBuffer.pTableBuffer[0] = - (M4OSA_MemAddr8)pC->ewc.WriterAudioAU.dataAddress; - pEncOutBuffer.pTableBufferSize[0] = 0; - - M4OSA_TRACE2_0("N **** blend AUs"); - -#ifdef M4VSS_SUPPORT_OMX_CODECS - /*OMX Audio decoder used. - * OMX Audio dec shell does internal buffering and hence does not return - a PCM buffer for every decodeStep call.* - * So PCM buffer sizes might be 0. In this case donot call encode Step*/ - - if( 0 != pEncInBuffer.pTableBufferSize[0] ) - { - -#endif - - /** - * Encode the PCM audio */ - - err = pC->ShellAPI.pAudioEncoderGlobalFcts->pFctStep( - pC->ewc.pAudioEncCtxt, &pEncInBuffer, &pEncOutBuffer); - - if( ( M4NO_ERROR != err) && (M4WAR_NO_MORE_AU != err) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio():\ - pAudioEncoderGlobalFcts->pFctStep returns 0x%x", - err); - return err; - } -#ifdef M4VSS_SUPPORT_OMX_CODECS - - } - -#endif - - /** - * Set AU cts and size */ - - pC->ewc.WriterAudioAU.size = pEncOutBuffer.pTableBufferSize[ - 0]; /**< Get the size of encoded data */ - pC->ewc.WriterAudioAU.CTS += frameTimeDelta; - - M4OSA_TRACE2_2("O ---- write : cts = %ld [ 0x%x ]", - (M4OSA_Int32)(pC->ewc.WriterAudioAU.CTS / pC->ewc.scale_audio), - pC->ewc.WriterAudioAU.size); - - /** - * Write the AU */ - err = pC->ShellAPI.pWriterDataFcts->pProcessAU( - pC->ewc.p3gpWriterContext, M4VSS3GPP_WRITER_AUDIO_STREAM_ID, - &pC->ewc.WriterAudioAU); - - if( M4NO_ERROR != err ) - { - /*11/12/2008 CR 3283 MMS use case for VideoArtist - the warning M4WAR_WRITER_STOP_REQ is returned when the targeted output - file size is reached - The editing is then finished,the warning M4VSS3GPP_WAR_EDITING_DONE - is returned*/ - if( M4WAR_WRITER_STOP_REQ == err ) - { - M4OSA_TRACE1_0( - "M4VSS3GPP_intEditStepAudio: File was cut to avoid oversize"); - return M4VSS3GPP_WAR_EDITING_DONE; - } - else - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION:\ - pWriterDataFcts->pProcessAU returns 0x%x!", - err); - return err; - } - } - - /** - * Read the next audio frame */ - err = M4VSS3GPP_intClipReadNextAudioFrame(pC->pC1); - - M4OSA_TRACE2_3("P .... read : cts = %.0f + %.0f [ 0x%x ]", - pC->pC1->iAudioFrameCts / pC->pC1->scale_audio, - pC->pC1->iAoffset / pC->pC1->scale_audio, - pC->pC1->uiAudioFrameSize); - - if( M4OSA_ERR_IS_ERROR(err) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION:\ - M4VSS3GPP_intClipReadNextAudioFrame(C1) returns 0x%x!", - err); - return err; - } - else - { - M4OSA_ERR secondaryError; - - /** - * Update current time (to=tc+T) */ - pC->ewc.dATo = ( pC->pC1->iAudioFrameCts + pC->pC1->iAoffset) - / pC->pC1->scale_audio; - - /** - * Read the next audio frame in the second clip */ - secondaryError = M4VSS3GPP_intClipReadNextAudioFrame(pC->pC2); - - M4OSA_TRACE2_3("Q .... read : cts = %.0f + %.0f [ 0x%x ]", - pC->pC2->iAudioFrameCts / pC->pC2->scale_audio, - pC->pC2->iAoffset / pC->pC2->scale_audio, - pC->pC2->uiAudioFrameSize); - - if( M4OSA_ERR_IS_ERROR(secondaryError) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: TRANSITION:\ - M4VSS3GPP_intClipReadNextAudioFrame(C2) returns 0x%x!", - secondaryError); - return err; - } - - if( ( ( M4WAR_NO_MORE_AU == err) - || (M4WAR_NO_MORE_AU == secondaryError)) - && (M4OSA_FALSE == pC->bSupportSilence) ) - { - /** - * If output is other than AMR or AAC - (i.e. EVRC,we can't write silence into it) - * So we simply end here.*/ - bStopAudio = M4OSA_TRUE; - } - } - } - break; - - /* ____________ */ - /*| |*/ - /*| ERROR CASE |*/ - /*|____________|*/ - - default: - - M4OSA_TRACE3_1( - "M4VSS3GPP_intEditStepAudio: invalid internal state (0x%x), \ - returning M4VSS3GPP_ERR_INTERNAL_STATE", - pC->Astate); - return M4VSS3GPP_ERR_INTERNAL_STATE; - } - - /** - * Check if we are forced to stop audio */ - if( M4OSA_TRUE == bStopAudio ) - { - /** - * Audio is done for this clip */ - err = M4VSS3GPP_intReachedEndOfAudio(pC); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intEditStepAudio: M4VSS3GPP_intReachedEndOfAudio returns 0x%x", - err); - return err; - } - } - - /** - * Return with no error */ - M4OSA_TRACE3_0("M4VSS3GPP_intEditStepAudio: returning M4NO_ERROR"); - return M4NO_ERROR; -} - -/** - ****************************************************************************** - * M4OSA_ERR M4VSS3GPP_intCheckAudioMode() - * @brief Check which audio process mode we must use, depending on the output CTS. - * @param pC (IN/OUT) Internal edit context - ****************************************************************************** - */ -static M4OSA_ERR M4VSS3GPP_intCheckAudioMode( M4VSS3GPP_InternalEditContext - *pC ) -{ - M4OSA_ERR err; - const M4OSA_Int32 TD = pC->pTransitionList[pC-> - uiCurrentClip].uiTransitionDuration; /**< Transition duration */ - - const M4VSS3GPP_EditAudioState previousAstate = pC->Astate; - - /** - * Check if Clip1 is on its begin cut, or in its begin effect or end effect zone */ - M4VSS3GPP_intCheckAudioEffects(pC, 1); - - /** - * Check if we are in the transition with next clip */ - if( ( TD > 0) && ((M4OSA_Int32)(pC->ewc.dATo - pC->pC1->iAoffset - / pC->pC1->scale_audio + 0.5) >= (pC->pC1->iEndTime - TD)) ) - { - /** - * We are in a transition */ - pC->Astate = M4VSS3GPP_kEditAudioState_TRANSITION; - pC->bTransitionEffect = M4OSA_TRUE; - - /** - * Do we enter the transition section ? */ - if( M4VSS3GPP_kEditAudioState_TRANSITION != previousAstate ) - { - /** - * Open second clip for transition, if not yet opened */ - if( M4OSA_NULL == pC->pC2 ) - { - err = M4VSS3GPP_intOpenClip(pC, &pC->pC2, - &pC->pClipList[pC->uiCurrentClip + 1]); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intCheckAudioMode: M4VSS3GPP_intOpenClip() returns 0x%x!", - err); - return err; - } - - /** - * In case of short transition and bad luck (...), there may be no video AU - * in the transition. In that case, the second clip has not been opened. - * So we must update the video offset here. */ - // Decorrelate input and output encoding timestamp to handle encoder prefetch - /**< Add current video output CTS to the clip offset */ - pC->pC2->iVoffset += (M4OSA_UInt32)pC->ewc.dInputVidCts; - } - - /** - * Add current audio output CTS to the clip offset - * (video offset has already been set when doing the video transition) */ - pC->pC2->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->pC2->iAoffset - - (M4OSA_Int32)(pC->pC2->iVoffset *pC->pC2->scale_audio + 0.5)) - > pC->ewc.iSilenceFrameDuration ) - { - /** - * Advance one AMR frame */ - err = M4VSS3GPP_intClipReadNextAudioFrame(pC->pC2); - - M4OSA_TRACE2_3("Z .... read : cts = %.0f + %.0f [ 0x%x ]", - pC->pC2->iAudioFrameCts / pC->pC2->scale_audio, - pC->pC2->iAoffset / pC->pC2->scale_audio, - pC->pC2->uiAudioFrameSize); - - if( M4OSA_ERR_IS_ERROR(err) ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intCheckAudioMode:\ - M4VSS3GPP_intClipReadNextAudioFrame returns 0x%x!", - err); - return err; - } - /** - * Update audio offset accordingly*/ - pC->pC2->iAoffset -= pC->ewc.iSilenceFrameDuration; - } - } - - /** - * Check begin and end effects for clip2 */ - M4VSS3GPP_intCheckAudioEffects(pC, 2); - } - else - { - /** - * We are not in a transition */ - pC->bTransitionEffect = M4OSA_FALSE; - - /** - * Check if current mode is Read/Write or Decode/Encode */ - if( pC->iClip1ActiveEffect >= 0 ) - { - pC->Astate = M4VSS3GPP_kEditAudioState_DECODE_ENCODE; - } - else - { - pC->Astate = M4VSS3GPP_kEditAudioState_READ_WRITE; - } - } - - /** - * Check if we create/destroy an encoder */ - if( ( M4VSS3GPP_kEditAudioState_READ_WRITE == previousAstate) - && /**< read mode */ - (M4VSS3GPP_kEditAudioState_READ_WRITE != pC->Astate) ) /**< encode mode */ - { - M4OSA_UInt32 uiAudioBitrate; - - /* Compute max bitrate depending on input files bitrates and transitions */ - if( pC->Astate == M4VSS3GPP_kEditAudioState_TRANSITION ) - { - /* Max of the two blended files */ - if( pC->pC1->pSettings->ClipProperties.uiAudioBitrate - > pC->pC2->pSettings->ClipProperties.uiAudioBitrate ) - uiAudioBitrate = - pC->pC1->pSettings->ClipProperties.uiAudioBitrate; - else - uiAudioBitrate = - pC->pC2->pSettings->ClipProperties.uiAudioBitrate; - } - else - { - /* Same as input file */ - uiAudioBitrate = pC->pC1->pSettings->ClipProperties.uiAudioBitrate; - } - - /** - * Create the encoder */ - err = M4VSS3GPP_intCreateAudioEncoder(&pC->ewc, &pC->ShellAPI, - uiAudioBitrate); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intCheckAudioMode: M4VSS3GPP_intResetAudioEncoder() returns 0x%x!", - err); - return err; - } - } - - /** - * Return with no error */ - M4OSA_TRACE3_0("M4VSS3GPP_intCheckAudioMode(): returning M4NO_ERROR"); - return M4NO_ERROR; -} - -/** - ****************************************************************************** - * M4OSA_Void M4VSS3GPP_intCheckAudioEffects() - * @brief Check which audio effect must be applied at the current time - ****************************************************************************** - */ -static M4OSA_Void M4VSS3GPP_intCheckAudioEffects( M4VSS3GPP_InternalEditContext - *pC, M4OSA_UInt8 uiClipNumber ) -{ - M4OSA_UInt8 uiClipIndex; - M4OSA_UInt8 uiFxIndex; - M4VSS3GPP_ClipContext *pClip; - M4VSS3GPP_EffectSettings *pFx; - M4OSA_Int32 BC, EC; - M4OSA_Int8 *piClipActiveEffect; - M4OSA_Int32 t; - - if( 1 == uiClipNumber ) - { - uiClipIndex = pC->uiCurrentClip; - pClip = pC->pC1; - piClipActiveEffect = &(pC->iClip1ActiveEffect); - } - else /**< (2 == uiClipNumber) */ - { - uiClipIndex = pC->uiCurrentClip + 1; - pClip = pC->pC2; - piClipActiveEffect = &(pC->iClip2ActiveEffect); - } - - /** - * Shortcuts for code readability */ - BC = pClip->iActualAudioBeginCut; - EC = pClip->iEndTime; - - /** - Change the absolut time to clip related time - RC t = (M4OSA_Int32)(pC->ewc.dATo - pClip->iAoffset/pClip->scale_audio + 0.5); - < rounding */; - t = (M4OSA_Int32)(pC->ewc.dATo/*- pClip->iAoffset/pClip->scale_audio*/ - + 0.5); /**< rounding */ - ; - - /** - * Default: no effect active */ - *piClipActiveEffect = -1; - - /** - * Check the three effects */ - // RC for (uiFxIndex=0; uiFxIndex<pC->pClipList[uiClipIndex].nbEffects; uiFxIndex++) - for ( uiFxIndex = 0; uiFxIndex < pC->nbEffects; uiFxIndex++ ) - { - /** Shortcut, reverse order because of priority between effects - ( EndEffect always clean ) */ - pFx = &(pC->pEffectsList[pC->nbEffects - 1 - uiFxIndex]); - - if( M4VSS3GPP_kAudioEffectType_None != pFx->AudioEffectType ) - { - /** - * Check if there is actually a video effect */ - if( ( t >= (M4OSA_Int32)(/*BC +*/pFx->uiStartTime)) - && /**< Are we after the start time of the effect? */ - (t < (M4OSA_Int32)(/*BC +*/pFx->uiStartTime + pFx-> - uiDuration)) ) /**< Are we into the effect duration? */ - { - /** - * Set the active effect */ - *piClipActiveEffect = pC->nbEffects - 1 - uiFxIndex; - - /** - * The first effect has the highest priority, then the second one, - then the thirs one. - * Hence, as soon as we found an active effect, we can get out of this loop */ - uiFxIndex = pC->nbEffects; /** get out of the for loop */ - } - /** - * Bugfix: The duration of the end effect has been set according to the - announced clip duration. - * If the announced duration is smaller than the real one, the end effect - won't be applied at - * the very end of the clip. To solve this issue we force the end effect. */ - - } - } - - return; -} - -/** - ****************************************************************************** - * M4OSA_ERR M4VSS3GPP_intApplyAudioEffect() - * @brief Apply audio effect to pPCMdata - * @param pC (IN/OUT) Internal edit context - * @param uiClip1orClip2 (IN/OUT) 1 for first clip, 2 for second clip - * @param pPCMdata (IN/OUT) Input and Output PCM audio data - * @param uiPCMsize (IN) Size of pPCMdata - * @return M4NO_ERROR: No error - ****************************************************************************** - */ -static M4OSA_ERR M4VSS3GPP_intApplyAudioEffect( M4VSS3GPP_InternalEditContext - *pC, M4OSA_UInt8 uiClip1orClip2, - M4OSA_Int16 *pPCMdata, - M4OSA_UInt32 uiPCMsize ) -{ - M4VSS3GPP_ClipContext *pClip; - M4VSS3GPP_ClipSettings *pClipSettings; - M4VSS3GPP_EffectSettings *pFx; - M4OSA_Int32 - i32sample; /**< we will cast each Int16 sample into this Int32 variable */ - M4OSA_Int32 iPos; - M4OSA_Int32 iDur; - - M4OSA_DEBUG_IF2(( 1 != uiClip1orClip2) && (2 != uiClip1orClip2), - M4ERR_PARAMETER, - "M4VSS3GPP_intBeginAudioEffect: uiClip1orClip2 invalid"); - - if( 1 == uiClip1orClip2 ) - { - pClip = pC->pC1; - pClipSettings = &(pC->pClipList[pC-> - uiCurrentClip]); /**< Get a shortcut to the clip settings */ - // RC pFx = &(pClipSettings->Effects[pC->iClip1ActiveEffect]);/**< Get a shortcut - // to the active effect */ - pFx = &(pC-> - pEffectsList[pC-> - iClip1ActiveEffect]); /**< Get a shortcut to the active effect */ - M4OSA_DEBUG_IF2(( pC->iClip1ActiveEffect < 0) - || (pC->iClip1ActiveEffect > 2), M4ERR_PARAMETER, - "M4VSS3GPP_intApplyAudioEffect: iClip1ActiveEffect invalid"); - } - else /**< if (2==uiClip1orClip2) */ - { - pClip = pC->pC2; - pClipSettings = &(pC->pClipList[pC->uiCurrentClip - + 1]); /**< Get a shortcut to the clip settings */ - // RC pFx = &(pClipSettings->Effects[pC->iClip2ActiveEffect]);/**< Get a shortcut - // to the active effect */ - pFx = &(pC-> - pEffectsList[pC-> - iClip2ActiveEffect]); /**< Get a shortcut to the active effect */ - M4OSA_DEBUG_IF2(( pC->iClip2ActiveEffect < 0) - || (pC->iClip2ActiveEffect > 2), M4ERR_PARAMETER, - "M4VSS3GPP_intApplyAudioEffect: iClip2ActiveEffect invalid"); - } - - iDur = (M4OSA_Int32)pFx->uiDuration; - - /** - * Compute how far from the beginning of the effect we are, in clip-base time. - * It is done with integers because the offset and begin cut have been rounded already. */ - iPos = - (M4OSA_Int32)(pC->ewc.dATo + 0.5 - pClip->iAoffset / pClip->scale_audio) - - pClip->iActualAudioBeginCut - pFx->uiStartTime; - - /** - * Sanity check */ - if( iPos > iDur ) - { - iPos = iDur; - } - else if( iPos < 0 ) - { - iPos = 0; - } - - /** - * At this point, iPos is the effect progress, in a 0 to iDur base */ - switch( pFx->AudioEffectType ) - { - case M4VSS3GPP_kAudioEffectType_FadeIn: - - /** - * Original samples are signed 16bits. - * We convert it to signed 32bits and multiply it by iPos. - * So we must assure that iPos is not higher that 16bits max. - * iPos max value is iDur, so we test iDur. */ - while( iDur > PWR_FXP_FRACT_MAX ) - { - iDur >>= - 2; /**< divide by 2 would be more logical (instead of 4), - but we have enough dynamic..) */ - iPos >>= 2; /**< idem */ - } - - /** - * From buffer size (bytes) to number of sample (int16): divide by two */ - uiPCMsize >>= 1; - - /** - * Loop on samples */ - while( uiPCMsize-- > 0 ) /**< decrementing to optimize */ - { - i32sample = *pPCMdata; - i32sample *= iPos; - i32sample /= iDur; - *pPCMdata++ = (M4OSA_Int16)i32sample; - } - - break; - - case M4VSS3GPP_kAudioEffectType_FadeOut: - - /** - * switch from 0->Dur to Dur->0 in order to do fadeOUT instead of fadeIN */ - iPos = iDur - iPos; - - /** - * Original samples are signed 16bits. - * We convert it to signed 32bits and multiply it by iPos. - * So we must assure that iPos is not higher that 16bits max. - * iPos max value is iDur, so we test iDur. */ - while( iDur > PWR_FXP_FRACT_MAX ) - { - iDur >>= - 2; /**< divide by 2 would be more logical (instead of 4), - but we have enough dynamic..) */ - iPos >>= 2; /**< idem */ - } - - /** - * From buffer size (bytes) to number of sample (int16): divide by two */ - uiPCMsize >>= 1; - - /** - * Loop on samples, apply the fade factor on each */ - while( uiPCMsize-- > 0 ) /**< decrementing counter to optimize */ - { - i32sample = *pPCMdata; - i32sample *= iPos; - i32sample /= iDur; - *pPCMdata++ = (M4OSA_Int16)i32sample; - } - - break; - - default: - M4OSA_TRACE1_1( - "M4VSS3GPP_intApplyAudioEffect: unknown audio effect type (0x%x),\ - returning M4VSS3GPP_ERR_INVALID_AUDIO_EFFECT_TYPE", - pFx->AudioEffectType); - return M4VSS3GPP_ERR_INVALID_AUDIO_EFFECT_TYPE; - } - - /** - * Return */ - M4OSA_TRACE3_0("M4VSS3GPP_intApplyAudioEffect: returning M4NO_ERROR"); - return M4NO_ERROR; -} - -/** - ****************************************************************************** - * M4OSA_ERR M4VSS3GPP_intAudioTransition() - * @brief Apply transition effect to two PCM buffer - * @note The result of the transition is put in the first buffer. - * I know it's not beautiful, but it fits my current needs, and it's efficient! - * So why bother with a third output buffer? - * @param pC (IN/OUT) Internal edit context - * @param pPCMdata1 (IN/OUT) First input and Output PCM audio data - * @param pPCMdata2 (IN) Second input PCM audio data - * @param uiPCMsize (IN) Size of both PCM buffers - * @return M4NO_ERROR: No error - ****************************************************************************** - */ -static M4OSA_ERR M4VSS3GPP_intAudioTransition( M4VSS3GPP_InternalEditContext - *pC, M4OSA_Int16 *pPCMdata1, - M4OSA_Int16 *pPCMdata2, - M4OSA_UInt32 uiPCMsize ) -{ - M4OSA_Int32 i32sample1, - i32sample2; /**< we will cast each Int16 sample into this Int32 variable */ - M4OSA_Int32 iPos1, iPos2; - M4OSA_Int32 iDur = (M4OSA_Int32)pC-> - pTransitionList[pC->uiCurrentClip].uiTransitionDuration; - - /** - * Compute how far from the end cut we are, in clip-base time. - * It is done with integers because the offset and begin cut have been rounded already. */ - iPos1 = pC->pC1->iEndTime - (M4OSA_Int32)(pC->ewc.dATo - + 0.5 - pC->pC1->iAoffset / pC->pC1->scale_audio); - - /** - * Sanity check */ - if( iPos1 > iDur ) - { - iPos1 = iDur; - } - else if( iPos1 < 0 ) - { - iPos1 = 0; - } - - /** - * Position of second clip in the transition */ - iPos2 = iDur - iPos1; - - /** - * At this point, iPos2 is the transition progress, in a 0 to iDur base. - * iPos1 is the transition progress, in a iDUr to 0 base. */ - switch( pC->pTransitionList[pC->uiCurrentClip].AudioTransitionType ) - { - case M4VSS3GPP_kAudioTransitionType_CrossFade: - - /** - * Original samples are signed 16bits. - * We convert it to signed 32bits and multiply it by iPos. - * So we must assure that iPos is not higher that 16bits max. - * iPos max value is iDur, so we test iDur. */ - while( iDur > PWR_FXP_FRACT_MAX ) - { - iDur >>= - 2; /**< divide by 2 would be more logical (instead of 4), - but we have enough dynamic..) */ - iPos1 >>= 2; /**< idem */ - iPos2 >>= 2; /**< idem */ - } - - /** - * From buffer size (bytes) to number of sample (int16): divide by two */ - uiPCMsize >>= 1; - - /** - * Loop on samples, apply the fade factor on each */ - while( uiPCMsize-- > 0 ) /**< decrementing counter to optimize */ - { - i32sample1 = *pPCMdata1; /**< Get clip1 sample */ - i32sample1 *= iPos1; /**< multiply by fade numerator */ - i32sample1 /= iDur; /**< divide by fade denominator */ - - i32sample2 = *pPCMdata2; /**< Get clip2 sample */ - i32sample2 *= iPos2; /**< multiply by fade numerator */ - i32sample2 /= iDur; /**< divide by fade denominator */ - - *pPCMdata1++ = (M4OSA_Int16)(i32sample1 - + i32sample2); /**< mix the two samples */ - pPCMdata2++; /**< don't forget to increment the second buffer */ - } - break; - - case M4VSS3GPP_kAudioTransitionType_None: - /** - * This is a stupid-non optimized version of the None transition... - * We copy the PCM frames */ - if( iPos1 < (iDur >> 1) ) /**< second half of transition */ - { - /** - * Copy the input PCM to the output buffer */ - memcpy((void *)pPCMdata1, - (void *)pPCMdata2, uiPCMsize); - } - /** - * the output must be put in the first buffer. - * For the first half of the non-transition it's already the case! - * So we have nothing to do here... - */ - - break; - - default: - M4OSA_TRACE1_1( - "M4VSS3GPP_intAudioTransition: unknown transition type (0x%x),\ - returning M4VSS3GPP_ERR_INVALID_AUDIO_TRANSITION_TYPE", - pC->pTransitionList[pC->uiCurrentClip].AudioTransitionType); - return M4VSS3GPP_ERR_INVALID_AUDIO_TRANSITION_TYPE; - } - - /** - * Return */ - M4OSA_TRACE3_0("M4VSS3GPP_intAudioTransition: returning M4NO_ERROR"); - return M4NO_ERROR; -} - -/** - ****************************************************************************** - * M4OSA_ERR M4VSS3GPP_intCreateAudioEncoder() - * @brief Reset the audio encoder (Create it if needed) - * @note - ****************************************************************************** - */ -M4OSA_ERR M4VSS3GPP_intCreateAudioEncoder( M4VSS3GPP_EncodeWriteContext *pC_ewc, - M4VSS3GPP_MediaAndCodecCtxt *pC_ShellAPI, - M4OSA_UInt32 uiAudioBitrate ) -{ - M4OSA_ERR err; - - /** - * If an encoder already exist, we destroy it */ - if( M4OSA_NULL != pC_ewc->pAudioEncCtxt ) - { - err = pC_ShellAPI->pAudioEncoderGlobalFcts->pFctClose( - pC_ewc->pAudioEncCtxt); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intResetAudioEncoder: 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_intResetAudioEncoder:\ - pAudioEncoderGlobalFcts->pFctCleanUp returns 0x%x", err); - /**< don't return, we still have stuff to free */ - } - - pC_ewc->pAudioEncCtxt = M4OSA_NULL; - } - - /** - * Creates a new encoder */ - switch( pC_ewc->AudioStreamType ) - { - //EVRC - // case M4SYS_kEVRC: - // - // err = M4VSS3GPP_setCurrentAudioEncoder(&pC->ShellAPI, - // pC_ewc->AudioStreamType); - // M4ERR_CHECK_RETURN(err); - // - // pC_ewc->AudioEncParams.Format = M4ENCODER_kEVRC; - // pC_ewc->AudioEncParams.Frequency = M4ENCODER_k8000Hz; - // pC_ewc->AudioEncParams.ChannelNum = M4ENCODER_kMono; - // pC_ewc->AudioEncParams.Bitrate = M4VSS3GPP_EVRC_DEFAULT_BITRATE; - // break; - - case M4SYS_kAMR: - - err = M4VSS3GPP_setCurrentAudioEncoder(pC_ShellAPI, - pC_ewc->AudioStreamType); - M4ERR_CHECK_RETURN(err); - - pC_ewc->AudioEncParams.Format = M4ENCODER_kAMRNB; - pC_ewc->AudioEncParams.Frequency = M4ENCODER_k8000Hz; - pC_ewc->AudioEncParams.ChannelNum = M4ENCODER_kMono; - pC_ewc->AudioEncParams.Bitrate = M4VSS3GPP_AMR_DEFAULT_BITRATE; - pC_ewc->AudioEncParams.SpecifParam.AmrSID = M4ENCODER_kAmrNoSID; - break; - - case M4SYS_kAAC: - - err = M4VSS3GPP_setCurrentAudioEncoder(pC_ShellAPI, - pC_ewc->AudioStreamType); - M4ERR_CHECK_RETURN(err); - - pC_ewc->AudioEncParams.Format = M4ENCODER_kAAC; - - switch( pC_ewc->uiSamplingFrequency ) - { - case 8000: - pC_ewc->AudioEncParams.Frequency = M4ENCODER_k8000Hz; - break; - - case 16000: - pC_ewc->AudioEncParams.Frequency = M4ENCODER_k16000Hz; - break; - - case 22050: - pC_ewc->AudioEncParams.Frequency = M4ENCODER_k22050Hz; - break; - - case 24000: - pC_ewc->AudioEncParams.Frequency = M4ENCODER_k24000Hz; - break; - - case 32000: - pC_ewc->AudioEncParams.Frequency = M4ENCODER_k32000Hz; - break; - - case 44100: - pC_ewc->AudioEncParams.Frequency = M4ENCODER_k44100Hz; - break; - - case 48000: - pC_ewc->AudioEncParams.Frequency = M4ENCODER_k48000Hz; - break; - - default: - M4OSA_TRACE1_1( - "M4VSS3GPP_intCreateAudioEncoder: invalid input AAC sampling frequency\ - (%d Hz), returning M4VSS3GPP_ERR_AUDIO_DECODER_INIT_FAILED", - pC_ewc->uiSamplingFrequency); - return M4VSS3GPP_ERR_AUDIO_DECODER_INIT_FAILED; - } - pC_ewc->AudioEncParams.ChannelNum = (pC_ewc->uiNbChannels == 1) - ? M4ENCODER_kMono : M4ENCODER_kStereo; - pC_ewc->AudioEncParams.SpecifParam.AacParam.Regulation = - M4ENCODER_kAacRegulNone; //M4ENCODER_kAacBitReservoir - /* unused */ - pC_ewc->AudioEncParams.SpecifParam.AacParam.bIS = M4OSA_FALSE; - pC_ewc->AudioEncParams.SpecifParam.AacParam.bMS = M4OSA_FALSE; - pC_ewc->AudioEncParams.SpecifParam.AacParam.bPNS = M4OSA_FALSE; - pC_ewc->AudioEncParams.SpecifParam.AacParam.bTNS = M4OSA_FALSE; - /* TODO change into highspeed asap */ - pC_ewc->AudioEncParams.SpecifParam.AacParam.bHighSpeed = - M4OSA_FALSE; - - /* Quantify value (ceil one) */ - if( uiAudioBitrate <= 16000 ) - pC_ewc->AudioEncParams.Bitrate = 16000; - - else if( uiAudioBitrate <= 24000 ) - pC_ewc->AudioEncParams.Bitrate = 24000; - - else if( uiAudioBitrate <= 32000 ) - pC_ewc->AudioEncParams.Bitrate = 32000; - - else if( uiAudioBitrate <= 48000 ) - pC_ewc->AudioEncParams.Bitrate = 48000; - - else if( uiAudioBitrate <= 64000 ) - pC_ewc->AudioEncParams.Bitrate = 64000; - - else - pC_ewc->AudioEncParams.Bitrate = 96000; - - /* Special requirement of our encoder */ - if( ( pC_ewc->uiNbChannels == 2) - && (pC_ewc->AudioEncParams.Bitrate < 32000) ) - pC_ewc->AudioEncParams.Bitrate = 32000; - - break; - - default: - M4OSA_TRACE1_1( - "M4VSS3GPP_intResetAudioEncoder: Undefined output audio format (%d),\ - returning M4VSS3GPP_ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT", - pC_ewc->AudioStreamType); - return M4VSS3GPP_ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT; - } - - /* Initialise the audio encoder */ -#ifdef M4VSS_SUPPORT_OMX_CODECS - - M4OSA_TRACE3_1( - "M4VSS3GPP_intResetAudioEncoder:\ - pAudioEncoderGlobalFcts->pFctInit called with userdata 0x%x", - pC_ShellAPI->pCurrentAudioEncoderUserData); - err = pC_ShellAPI->pAudioEncoderGlobalFcts->pFctInit(&pC_ewc->pAudioEncCtxt, - pC_ShellAPI->pCurrentAudioEncoderUserData); - -#else - - err = pC_ShellAPI->pAudioEncoderGlobalFcts->pFctInit(&pC_ewc->pAudioEncCtxt, - M4OSA_NULL /* no HW encoder */); - -#endif - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intResetAudioEncoder: pAudioEncoderGlobalFcts->pFctInit returns 0x%x", - err); - return err; - } - - /* Open the audio encoder */ - err = pC_ShellAPI->pAudioEncoderGlobalFcts->pFctOpen(pC_ewc->pAudioEncCtxt, - &pC_ewc->AudioEncParams, &pC_ewc->pAudioEncDSI, - M4OSA_NULL /* no grabbing */); - - if( M4NO_ERROR != err ) - { - M4OSA_TRACE1_1( - "M4VSS3GPP_intResetAudioEncoder: pAudioEncoderGlobalFcts->pFctOpen returns 0x%x", - err); - return err; - } - - /** - * Return with no error */ - M4OSA_TRACE3_0("M4VSS3GPP_intResetAudioEncoder: returning M4NO_ERROR"); - return M4NO_ERROR; -} |