/*
* 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_AudioMixing.c
* @brief Video Studio Service 3GPP audio mixing implementation.
* @note
******************************************************************************
*/
/****************/
/*** Includes ***/
/****************/
#include "NXPSW_CompilerSwitches.h"
/**
* Our headers */
#include "M4VSS3GPP_API.h"
#include "M4VSS3GPP_InternalTypes.h"
#include "M4VSS3GPP_InternalFunctions.h"
#include "M4VSS3GPP_ErrorCodes.h"
/* Put the definition of silence frames here */
#define M4VSS3GPP_SILENCE_FRAMES
#include "M4VSS3GPP_InternalConfig.h"
/**
* OSAL headers */
#include "M4OSA_Memory.h" /**< OSAL memory management */
#include "M4OSA_Debug.h" /**< OSAL debug management */
#include "VideoEditorResampler.h"
/**
******************************************************************************
* @brief Static functions
******************************************************************************
*/
static M4OSA_ERR
M4VSS3GPP_intAudioMixingOpen( M4VSS3GPP_InternalAudioMixingContext *pC,
M4VSS3GPP_AudioMixingSettings *pSettings );
static M4OSA_ERR M4VSS3GPP_intAudioMixingStepVideo(
M4VSS3GPP_InternalAudioMixingContext *pC );
static M4OSA_ERR M4VSS3GPP_intAudioMixingStepAudioMix(
M4VSS3GPP_InternalAudioMixingContext *pC );
static M4OSA_ERR M4VSS3GPP_intAudioMixingStepAudioReplace(
M4VSS3GPP_InternalAudioMixingContext *pC );
static M4OSA_ERR M4VSS3GPP_intAudioMixingCopyOrig(
M4VSS3GPP_InternalAudioMixingContext *pC );
static M4OSA_ERR M4VSS3GPP_intAudioMixingCopyAdded(
M4VSS3GPP_InternalAudioMixingContext *pC );
static M4OSA_ERR M4VSS3GPP_intAudioMixingConvert(
M4VSS3GPP_InternalAudioMixingContext *pC );
static M4OSA_ERR M4VSS3GPP_intAudioMixingDoMixing(
M4VSS3GPP_InternalAudioMixingContext *pC );
static M4OSA_ERR M4VSS3GPP_intAudioMixingWriteSilence(
M4VSS3GPP_InternalAudioMixingContext *pC );
static M4OSA_ERR M4VSS3GPP_intAudioMixingTransition(
M4VSS3GPP_InternalAudioMixingContext *pC );
static M4OSA_ERR M4VSS3GPP_intAudioMixingCreateVideoEncoder(
M4VSS3GPP_InternalAudioMixingContext *pC );
static M4OSA_ERR M4VSS3GPP_intAudioMixingDestroyVideoEncoder(
M4VSS3GPP_InternalAudioMixingContext *pC );
static M4OSA_Bool M4VSS3GPP_isThresholdBreached( M4OSA_Int32 *averageValue,
M4OSA_Int32 storeCount,
M4OSA_Int32 thresholdValue );
/**
* Internal warning */
#define M4VSS3GPP_WAR_END_OF_ADDED_AUDIO M4OSA_ERR_CREATE( M4_WAR, M4VSS3GPP, 0x0030)
/* A define used with SSRC 1.04 and above to avoid taking
blocks smaller that the minimal block size */
#define M4VSS_SSRC_MINBLOCKSIZE 600
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_audioMixingInit(M4VSS3GPP_AudioMixingContext* pContext,
* M4VSS3GPP_AudioMixingSettings* pSettings)
* @brief Initializes the VSS audio mixing operation (allocates an execution context).
* @note
* @param pContext (OUT) Pointer on the VSS audio mixing context to allocate
* @param pSettings (IN) Pointer to valid audio mixing settings
* @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 (debug only)
* @return M4ERR_ALLOC: There is no more available memory
******************************************************************************
*/
M4OSA_ERR M4VSS3GPP_audioMixingInit( M4VSS3GPP_AudioMixingContext *pContext,
M4VSS3GPP_AudioMixingSettings *pSettings,
M4OSA_FileReadPointer *pFileReadPtrFct,
M4OSA_FileWriterPointer *pFileWritePtrFct )
{
M4VSS3GPP_InternalAudioMixingContext *pC;
M4OSA_ERR err;
M4OSA_TRACE3_2(
"M4VSS3GPP_audioMixingInit called with pContext=0x%x, pSettings=0x%x",
pContext, pSettings);
/**
* Check input parameters */
M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER,
"M4VSS3GPP_audioMixingInit: pContext is M4OSA_NULL");
M4OSA_DEBUG_IF2((M4OSA_NULL == pSettings), M4ERR_PARAMETER,
"M4VSS3GPP_audioMixingInit: pSettings is M4OSA_NULL");
M4OSA_DEBUG_IF2((M4OSA_NULL == pFileReadPtrFct), M4ERR_PARAMETER,
"M4VSS3GPP_audioMixingInit: pFileReadPtrFct is M4OSA_NULL");
M4OSA_DEBUG_IF2((M4OSA_NULL == pFileWritePtrFct), M4ERR_PARAMETER,
"M4VSS3GPP_audioMixingInit: pFileWritePtrFct is M4OSA_NULL");
if( pSettings->uiBeginLoop > pSettings->uiEndLoop )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_audioMixingInit: Begin loop time is higher than end loop time!");
return M4VSS3GPP_ERR_BEGINLOOP_HIGHER_ENDLOOP;
}
/**
* Allocate the VSS audio mixing context and return it to the user */
pC = (M4VSS3GPP_InternalAudioMixingContext
*)M4OSA_32bitAlignedMalloc(sizeof(M4VSS3GPP_InternalAudioMixingContext),
M4VSS3GPP,(M4OSA_Char *)"M4VSS3GPP_InternalAudioMixingContext");
*pContext = pC;
if( M4OSA_NULL == pC )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_audioMixingInit(): unable to allocate \
M4VSS3GPP_InternalAudioMixingContext,returning M4ERR_ALLOC");
return M4ERR_ALLOC;
}
/* Initialization of context Variables */
memset((void *)pC ,0,
sizeof(M4VSS3GPP_InternalAudioMixingContext));
/**
* Copy this setting in context */
pC->iAddCts = pSettings->uiAddCts;
pC->bRemoveOriginal = pSettings->bRemoveOriginal;
pC->b_DuckingNeedeed = pSettings->b_DuckingNeedeed;
pC->InDucking_threshold = pSettings->InDucking_threshold;
pC->fBTVolLevel = pSettings->fBTVolLevel;
pC->fPTVolLevel = pSettings->fPTVolLevel;
pC->InDucking_lowVolume = pSettings->InDucking_lowVolume;
pC->bDoDucking = M4OSA_FALSE;
pC->bLoop = pSettings->bLoop;
pC->bNoLooping = M4OSA_FALSE;
pC->bjumpflag = M4OSA_TRUE;
/**
* Init some context variables */
pC->pInputClipCtxt = M4OSA_NULL;
pC->pAddedClipCtxt = M4OSA_NULL;
pC->fOrigFactor = 1.0F;
pC->fAddedFactor = 0.0F;
pC->bSupportSilence = M4OSA_FALSE;
pC->bHasAudio = M4OSA_FALSE;
pC->bAudioMixingIsNeeded = M4OSA_FALSE;
/* Init PC->ewc members */
// Decorrelate input and output encoding timestamp to handle encoder prefetch
pC->ewc.VideoStreamType = M4SYS_kVideoUnknown;
pC->ewc.bVideoDataPartitioning = M4OSA_FALSE;
pC->ewc.pVideoOutputDsi = M4OSA_NULL;
pC->ewc.AudioStreamType = M4SYS_kAudioUnknown;
pC->ewc.uiNbChannels = 1;
pC->ewc.pAudioOutputDsi = M4OSA_NULL;
pC->ewc.pAudioEncCtxt = M4OSA_NULL;
pC->ewc.pAudioEncDSI.pInfo = M4OSA_NULL;
pC->ewc.pSilenceFrameData = M4OSA_NULL;
pC->ewc.pEncContext = M4OSA_NULL;
pC->ewc.pDummyAuBuffer = M4OSA_NULL;
pC->ewc.p3gpWriterContext = M4OSA_NULL;
pC->pLVAudioResampler = M4OSA_NULL;
/**
* Set the OSAL filesystem function set */
pC->pOsaFileReadPtr = pFileReadPtrFct;
pC->pOsaFileWritPtr = pFileWritePtrFct;
/**
* Ssrc stuff */
pC->b_SSRCneeded = M4OSA_FALSE;
pC->pSsrcBufferIn = M4OSA_NULL;
pC->pSsrcBufferOut = M4OSA_NULL;
pC->pTempBuffer = M4OSA_NULL;
pC->pPosInTempBuffer = M4OSA_NULL;
pC->pPosInSsrcBufferIn = M4OSA_NULL;
pC->pPosInSsrcBufferOut = M4OSA_NULL;
pC->SsrcScratch = M4OSA_NULL;
pC->uiBeginLoop = pSettings->uiBeginLoop;
pC->uiEndLoop = pSettings->uiEndLoop;
/*
* 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);
/**
* Open input clip, added clip and output clip and proceed with the settings */
err = M4VSS3GPP_intAudioMixingOpen(pC, pSettings);
M4ERR_CHECK_RETURN(err);
/**
* Update main state automaton */
if( M4OSA_NULL != pC->pInputClipCtxt->pVideoStream )
pC->State = M4VSS3GPP_kAudioMixingState_VIDEO;
else
pC->State = M4VSS3GPP_kAudioMixingState_AUDIO_FIRST_SEGMENT;
pC->ewc.iOutputDuration = (M4OSA_Int32)pC->pInputClipCtxt->pSettings->
ClipProperties.uiClipDuration;
/*gInputParams.lvBTChannelCount*/
pC->pLVAudioResampler = LVAudioResamplerCreate(16,
pC->pAddedClipCtxt->pSettings->ClipProperties.uiNbChannels,
/* gInputParams.lvOutSampleRate*/(M4OSA_Int32)pSettings->outputASF, 1);
if( M4OSA_NULL == pC->pLVAudioResampler )
{
return M4ERR_ALLOC;
}
LVAudiosetSampleRate(pC->pLVAudioResampler,
/*gInputParams.lvInSampleRate*/
pC->pAddedClipCtxt->pSettings->ClipProperties.uiSamplingFrequency);
LVAudiosetVolume(pC->pLVAudioResampler,
(M4OSA_Int16)(0x1000 ),
(M4OSA_Int16)(0x1000 ));
/**
* Return with no error */
M4OSA_TRACE3_0("M4VSS3GPP_audioMixingInit(): returning M4NO_ERROR");
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_audioMixingStep(M4VSS3GPP_AudioMixingContext pContext)
* @brief Perform one step of audio mixing.
* @note
* @param pContext (IN) VSS audio mixing context
* @return M4NO_ERROR: No error
* @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only)
* @param pProgress (OUT) Progress percentage (0 to 100) of the finalization operation
* @return M4ERR_STATE: VSS is not in an appropriate state for this function to be called
* @return M4VSS3GPP_WAR_END_OF_AUDIO_MIXING: Audio mixing is over, user should now call
* M4VSS3GPP_audioMixingCleanUp()
******************************************************************************
*/
M4OSA_ERR M4VSS3GPP_audioMixingStep( M4VSS3GPP_AudioMixingContext pContext,
M4OSA_UInt8 *pProgress )
{
M4OSA_ERR err;
M4VSS3GPP_InternalAudioMixingContext *pC =
(M4VSS3GPP_InternalAudioMixingContext *)pContext;
M4OSA_TRACE3_1("M4VSS3GPP_audioMixingStep called with pContext=0x%x",
pContext);
/**
* Check input parameters */
M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER,
"M4VSS3GPP_audioMixingStep: pContext is M4OSA_NULL");
/**
* State automaton */
switch( pC->State )
{
case M4VSS3GPP_kAudioMixingState_VIDEO:
err = M4VSS3GPP_intAudioMixingStepVideo(pC);
/**
* Compute the progress percentage
* Note: audio and video CTS are not initialized before
* the call of M4VSS3GPP_intAudioMixingStepVideo */
/* P4ME00003276: First 0-50% segment is dedicated to state :
M4VSS3GPP_kAudioMixingState_VIDEO */
*pProgress = (M4OSA_UInt8)(50 * (pC->ewc.WriterVideoAU.CTS)
/ pC->pInputClipCtxt->pVideoStream->
m_basicProperties.m_duration);
/**
* There may be no audio track (Remove audio track feature).
* In that case we double the current percentage */
if( M4SYS_kAudioUnknown == pC->ewc.WriterAudioStream.streamType )
{
( *pProgress) <<= 1; /**< x2 */
}
else if( *pProgress >= 50 )
{
*pProgress =
49; /**< Video processing is not greater than 50% */
}
if( M4WAR_NO_MORE_AU == err )
{
if( pC->bHasAudio )
{
/**
* Video is over, state transition to audio and return OK */
if( pC->iAddCts > 0 )
pC->State =
M4VSS3GPP_kAudioMixingState_AUDIO_FIRST_SEGMENT;
else
pC->State =
M4VSS3GPP_kAudioMixingState_AUDIO_SECOND_SEGMENT;
}
else
{
/**
* No audio, state transition to FINISHED */
pC->State = M4VSS3GPP_kAudioMixingState_FINISHED;
}
return M4NO_ERROR;
}
else if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_audioMixingStep: M4VSS3GPP_intAudioMixingStepVideo returns 0x%x!",
err);
return err;
}
else
{
return M4NO_ERROR;
}
break;
case M4VSS3GPP_kAudioMixingState_AUDIO_FIRST_SEGMENT:
case M4VSS3GPP_kAudioMixingState_AUDIO_SECOND_SEGMENT:
case M4VSS3GPP_kAudioMixingState_AUDIO_THIRD_SEGMENT:
if( pC->pAddedClipCtxt->iAudioFrameCts
!= -pC->pAddedClipCtxt->iSilenceFrameDuration
&& (pC->pAddedClipCtxt->iAudioFrameCts - 0.5)
/ pC->pAddedClipCtxt->scale_audio > pC->uiEndLoop
&& pC->uiEndLoop > 0 )
{
if(pC->bLoop == M4OSA_FALSE)
{
pC->bNoLooping = M4OSA_TRUE;
}
else
{
M4OSA_Int32 jumpCTS = (M4OSA_Int32)(pC->uiBeginLoop);
err = pC->pAddedClipCtxt->ShellAPI.m_pReader->m_pFctJump(
pC->pAddedClipCtxt->pReaderContext,
(M4_StreamHandler *)pC->pAddedClipCtxt->
pAudioStream, &jumpCTS);
if( err != M4NO_ERROR )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_audioMixingStep: error when jumping in added audio clip: 0x%x",
err);
return err;
}
/**
* Use offset to give a correct CTS ... */
pC->pAddedClipCtxt->iAoffset =
(M4OSA_Int32)(pC->ewc.dATo * pC->ewc.scale_audio + 0.5);
}
}
if( M4OSA_FALSE == pC->bRemoveOriginal )
{
err = M4VSS3GPP_intAudioMixingStepAudioMix(pC);
}
else
{
err = M4VSS3GPP_intAudioMixingStepAudioReplace(pC);
}
/**
* Compute the progress percentage
* Note: audio and video CTS are not initialized before
* the call of M4VSS3GPP_intAudioMixingStepAudio */
if( 0 != pC->ewc.iOutputDuration )
{
/* P4ME00003276: Second 50-100% segment is dedicated to states :
M4VSS3GPP_kAudioMixingState_AUDIO... */
/* For Audio the progress computation is based on dAto and offset,
it is more accurate */
*pProgress = (M4OSA_UInt8)(50
+ (50 * pC->ewc.dATo - pC->pInputClipCtxt->iVoffset)
/ (pC->ewc.iOutputDuration)); /**< 50 for 100/2 **/
if( *pProgress >= 100 )
{
*pProgress =
99; /**< It's not really finished, I prefer to return less than 100% */
}
}
else
{
*pProgress = 99;
}
if( M4WAR_NO_MORE_AU == err )
{
/**
* Audio is over, state transition to FINISHED */
pC->State = M4VSS3GPP_kAudioMixingState_FINISHED;
return M4NO_ERROR;
}
else if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_audioMixingStep: M4VSS3GPP_intAudioMixingStepAudio returns 0x%x!",
err);
return err;
}
else
{
return M4NO_ERROR;
}
break;
case M4VSS3GPP_kAudioMixingState_FINISHED:
/**
* Progress percentage: finalize finished -> 100% */
*pProgress = 100;
/**
* Audio mixing is finished, return correct warning */
return M4VSS3GPP_WAR_END_OF_AUDIO_MIXING;
default:
M4OSA_TRACE1_1(
"M4VSS3GPP_audioMixingStep: State error (0x%x)! Returning M4ERR_STATE",
pC->State);
return M4ERR_STATE;
}
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_audioMixingCleanUp(M4VSS3GPP_AudioMixingContext pContext)
* @brief Free all resources used by the VSS audio mixing operation.
* @note The context is no more valid after this call
* @param pContext (IN) VSS audio mixing context
* @return M4NO_ERROR: No error
* @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only)
******************************************************************************
*/
M4OSA_ERR M4VSS3GPP_audioMixingCleanUp( M4VSS3GPP_AudioMixingContext pContext )
{
M4VSS3GPP_InternalAudioMixingContext *pC =
(M4VSS3GPP_InternalAudioMixingContext *)pContext;
M4OSA_ERR err;
M4OSA_UInt32 lastCTS;
M4OSA_TRACE3_1("M4VSS3GPP_audioMixingCleanUp called with pContext=0x%x",
pContext);
/**
* Check input parameters */
M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER,
"M4VSS3GPP_audioMixingCleanUp: pContext is M4OSA_NULL");
/**
* Check input parameter */
if( M4OSA_NULL == pContext )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_audioMixingCleanUp(): M4VSS3GPP_audioMixingCleanUp: pContext is\
M4OSA_NULL, returning M4ERR_PARAMETER");
return M4ERR_PARAMETER;
}
/**
* Close Input 3GPP file */
if( M4OSA_NULL != pC->pInputClipCtxt )
{
M4VSS3GPP_intClipCleanUp(pC->pInputClipCtxt);
pC->pInputClipCtxt = M4OSA_NULL;
}
/**
* Close Added 3GPP file */
if( M4OSA_NULL != pC->pAddedClipCtxt )
{
M4VSS3GPP_intClipCleanUp(pC->pAddedClipCtxt);
pC->pAddedClipCtxt = M4OSA_NULL;
}
/**
* Close the 3GP writer. In normal use case it has already been closed,
but not in abort use case */
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_audioMixingCleanUp: SetOption(M4WRITER_kMaxFileDuration) returns 0x%x",
err);
}
err = pC->ShellAPI.pWriterGlobalFcts->pFctCloseWrite(
pC->ewc.p3gpWriterContext);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_audioMixingCleanUp: pWriterGlobalFcts->pFctCloseWrite returns 0x%x!",
err);
/**< don't return the error because we have other things to free! */
}
pC->ewc.p3gpWriterContext = 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_audioMixingCleanUp: 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_audioMixingCleanUp: pAudioEncoderGlobalFcts->pFctCleanUp returns 0x%x",
err);
/**< don't return, we still have stuff to free */
}
pC->ewc.pAudioEncCtxt = M4OSA_NULL;
}
/**
* Free the ssrc stuff */
if( M4OSA_NULL != pC->SsrcScratch )
{
free(pC->SsrcScratch);
pC->SsrcScratch = M4OSA_NULL;
}
if( M4OSA_NULL != pC->pSsrcBufferIn )
{
free(pC->pSsrcBufferIn);
pC->pSsrcBufferIn = M4OSA_NULL;
}
if( M4OSA_NULL != pC->pSsrcBufferOut
&& (M4OSA_TRUE == pC->b_SSRCneeded || pC->ChannelConversion > 0) )
{
free(pC->pSsrcBufferOut);
pC->pSsrcBufferOut = M4OSA_NULL;
}
if( M4OSA_NULL != pC->pTempBuffer )
{
free(pC->pTempBuffer);
pC->pTempBuffer = M4OSA_NULL;
}
if (pC->pLVAudioResampler != M4OSA_NULL)
{
LVDestroy(pC->pLVAudioResampler);
pC->pLVAudioResampler = M4OSA_NULL;
}
/**
* Free the shells interfaces */
M4VSS3GPP_unRegisterAllWriters(&pC->ShellAPI);
M4VSS3GPP_unRegisterAllEncoders(&pC->ShellAPI);
M4VSS3GPP_unRegisterAllReaders(&pC->ShellAPI);
M4VSS3GPP_unRegisterAllDecoders(&pC->ShellAPI);
/**
* Free the context */
free(pContext);
pContext = M4OSA_NULL;
/**
* Return with no error */
M4OSA_TRACE3_0("M4VSS3GPP_audioMixingCleanUp(): returning M4NO_ERROR");
return M4NO_ERROR;
}
/******************************************************************************/
/******************************************************************************/
/********* STATIC FUNCTIONS **********/
/******************************************************************************/
/******************************************************************************/
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_intAudioMixingOpen()
* @brief Initializes the VSS audio mixing operation (allocates an execution context).
* @note
* @param pContext (OUT) Pointer on the VSS audio mixing context to allocate
* @param pSettings (IN) Pointer to valid audio mixing settings
* @return M4NO_ERROR: No error
* @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL (debug only)
* @return M4ERR_ALLOC: There is no more available memory
******************************************************************************
*/
static M4OSA_ERR
M4VSS3GPP_intAudioMixingOpen( M4VSS3GPP_InternalAudioMixingContext *pC,
M4VSS3GPP_AudioMixingSettings *pSettings )
{
M4OSA_ERR err;
M4OSA_UInt32 outputASF = 0;
M4ENCODER_Header *encHeader;
M4OSA_TRACE3_2(
"M4VSS3GPP_intAudioMixingOpen called with pContext=0x%x, pSettings=0x%x",
pC, pSettings);
/**
* The Add Volume must be (strictly) superior than zero */
if( pSettings->uiAddVolume == 0 )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen(): AddVolume is zero,\
returning M4VSS3GPP_ERR_ADDVOLUME_EQUALS_ZERO");
return M4VSS3GPP_ERR_ADDVOLUME_EQUALS_ZERO;
}
/*
else if(pSettings->uiAddVolume >= 100) // If volume is set to 100, no more original audio ...
{
pC->bRemoveOriginal = M4OSA_TRUE;
}
*/
/**
* Build the input clip settings */
pC->InputClipSettings.pFile =
pSettings->pOriginalClipFile; /**< Input 3GPP file descriptor */
pC->InputClipSettings.FileType = M4VIDEOEDITING_kFileType_3GPP;
pC->InputClipSettings.uiBeginCutTime =
0; /**< No notion of cut for the audio mixing feature */
pC->InputClipSettings.uiEndCutTime =
0; /**< No notion of cut for the audio mixing feature */
/**
* Open the original Audio/Video 3GPP clip */
err = M4VSS3GPP_intClipInit(&pC->pInputClipCtxt, pC->pOsaFileReadPtr);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen(): M4VSS3GPP_intClipInit(orig) returns 0x%x",
err);
return err;
}
err = M4VSS3GPP_intClipOpen(pC->pInputClipCtxt, &pC->InputClipSettings,
M4OSA_FALSE, M4OSA_FALSE, M4OSA_TRUE);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen(): M4VSS3GPP_intClipOpen(orig) returns 0x%x",
err);
return err;
}
if( M4OSA_NULL == pC->pInputClipCtxt->pAudioStream )
{
pC->bRemoveOriginal = M4OSA_TRUE;
}
/**
* If there is no video, it's an error */
if( M4OSA_NULL == pC->pInputClipCtxt->pVideoStream )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen(): no video stream in clip,\
returning M4VSS3GPP_ERR_NO_SUPPORTED_STREAM_IN_FILE");
return M4VSS3GPP_ERR_NO_SUPPORTED_STREAM_IN_FILE;
}
/**
* Compute clip properties */
err = M4VSS3GPP_intBuildAnalysis(pC->pInputClipCtxt,
&pC->pInputClipCtxt->pSettings->ClipProperties);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen(): M4VSS3GPP_intBuildAnalysis(orig) returns 0x%x",
err);
return err;
}
/**
* Build the added clip settings */
pC->AddedClipSettings.pFile =
pSettings->pAddedAudioTrackFile; /**< Added file descriptor */
pC->AddedClipSettings.FileType = pSettings->AddedAudioFileType;
pC->AddedClipSettings.uiBeginCutTime =
0; /**< No notion of cut for the audio mixing feature */
pC->AddedClipSettings.uiEndCutTime = 0;/**< No notion of cut for the audio mixing feature */
pC->AddedClipSettings.ClipProperties.uiNbChannels=
pSettings->uiNumChannels;
pC->AddedClipSettings.ClipProperties.uiSamplingFrequency= pSettings->uiSamplingFrequency;
if( M4OSA_NULL != pC->AddedClipSettings.pFile )
{
/**
* Open the added Audio clip */
err = M4VSS3GPP_intClipInit(&pC->pAddedClipCtxt, pC->pOsaFileReadPtr);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen(): M4VSS3GPP_intClipInit(added) returns 0x%x",
err);
return err;
}
err = M4VSS3GPP_intClipOpen(pC->pAddedClipCtxt, &pC->AddedClipSettings,
M4OSA_FALSE, M4OSA_FALSE, M4OSA_TRUE);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen(): M4VSS3GPP_intClipOpen(added) returns 0x%x",
err);
return err;
}
/**
* If there is no audio, it's an error */
if( M4OSA_NULL == pC->pAddedClipCtxt->pAudioStream )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen(): no audio nor video stream in clip,\
returning M4VSS3GPP_ERR_NO_SUPPORTED_STREAM_IN_FILE");
return M4VSS3GPP_ERR_NO_SUPPORTED_STREAM_IN_FILE;
}
/**
* Compute clip properties */
err = M4VSS3GPP_intBuildAnalysis(pC->pAddedClipCtxt,
&pC->pAddedClipCtxt->pSettings->ClipProperties);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen(): M4VSS3GPP_intBuildAnalysis(added) returns 0x%x",
err);
return err;
}
switch( pSettings->outputASF )
{
case M4VIDEOEDITING_k8000_ASF:
outputASF = 8000;
break;
case M4VIDEOEDITING_k16000_ASF:
outputASF = 16000;
break;
case M4VIDEOEDITING_k22050_ASF:
outputASF = 22050;
break;
case M4VIDEOEDITING_k24000_ASF:
outputASF = 24000;
break;
case M4VIDEOEDITING_k32000_ASF:
outputASF = 32000;
break;
case M4VIDEOEDITING_k44100_ASF:
outputASF = 44100;
break;
case M4VIDEOEDITING_k48000_ASF:
outputASF = 48000;
break;
default:
M4OSA_TRACE1_0("Bad parameter in output ASF ");
return M4ERR_PARAMETER;
break;
}
if( pC->bRemoveOriginal == M4OSA_TRUE
&& (pC->pAddedClipCtxt->pSettings->ClipProperties.AudioStreamType
== M4VIDEOEDITING_kMP3 || pC->pAddedClipCtxt->pSettings->
ClipProperties.AudioStreamType == M4VIDEOEDITING_kPCM
|| pC->pAddedClipCtxt->pSettings->
ClipProperties.AudioStreamType
!= pSettings->outputAudioFormat
|| pC->pAddedClipCtxt->pSettings->
ClipProperties.uiSamplingFrequency != outputASF
|| pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels
!= pSettings->outputNBChannels) )
{
if( pSettings->outputAudioFormat == M4VIDEOEDITING_kAMR_NB )
{
pSettings->outputASF = M4VIDEOEDITING_k8000_ASF;
pSettings->outputNBChannels = 1;
pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize = 320;
}
else if( pSettings->outputAudioFormat == M4VIDEOEDITING_kAAC )
{
pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize =
2048 * pSettings->outputNBChannels;
}
pC->pInputClipCtxt->pSettings->ClipProperties.uiSamplingFrequency =
outputASF;
if( outputASF != pC->pAddedClipCtxt->pSettings->
ClipProperties.uiSamplingFrequency )
{
/* We need to call SSRC in order to align ASF and/or nb of channels */
/* Moreover, audio encoder may be needed in case of audio replacing... */
pC->b_SSRCneeded = M4OSA_TRUE;
}
if( pSettings->outputNBChannels
< pC->pAddedClipCtxt->pSettings->ClipProperties.uiNbChannels )
{
/* Stereo to Mono */
pC->ChannelConversion = 1;
}
else if( pSettings->outputNBChannels
> pC->pAddedClipCtxt->pSettings->ClipProperties.uiNbChannels )
{
/* Mono to Stereo */
pC->ChannelConversion = 2;
}
pC->pInputClipCtxt->pSettings->ClipProperties.uiNbChannels =
pSettings->outputNBChannels;
}
/**
* Check compatibility chart */
err = M4VSS3GPP_intAudioMixingCompatibility(pC,
&pC->pInputClipCtxt->pSettings->ClipProperties,
&pC->pAddedClipCtxt->pSettings->ClipProperties);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen():\
M4VSS3GPP_intAudioMixingCompatibility returns 0x%x",
err);
return err;
}
/**
* Check loop parameters */
if( pC->uiBeginLoop > pC->pAddedClipCtxt->pSettings->
ClipProperties.uiClipAudioDuration )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen():\
begin loop time is higher than added clip audio duration");
return M4VSS3GPP_ERR_BEGINLOOP_HIGHER_ENDLOOP;
}
/**
* Ok, let's go with this audio track */
pC->bHasAudio = M4OSA_TRUE;
}
else
{
/* No added file, force remove original */
pC->AddedClipSettings.FileType = M4VIDEOEDITING_kFileType_Unsupported;
pC->bRemoveOriginal = M4OSA_TRUE;
pC->bHasAudio = M4OSA_FALSE;
}
/**
* Copy the video properties of the input clip to the output properties */
pC->ewc.uiVideoBitrate =
pC->pInputClipCtxt->pSettings->ClipProperties.uiVideoBitrate;
pC->ewc.uiVideoWidth =
pC->pInputClipCtxt->pSettings->ClipProperties.uiVideoWidth;
pC->ewc.uiVideoHeight =
pC->pInputClipCtxt->pSettings->ClipProperties.uiVideoHeight;
pC->ewc.uiVideoTimeScale =
pC->pInputClipCtxt->pSettings->ClipProperties.uiVideoTimeScale;
pC->ewc.bVideoDataPartitioning =
pC->pInputClipCtxt->pSettings->ClipProperties.bMPEG4dataPartition;
pC->ewc.outputVideoProfile =
pC->pInputClipCtxt->pSettings->ClipProperties.uiVideoProfile;
pC->ewc.outputVideoLevel =
pC->pInputClipCtxt->pSettings->ClipProperties.uiVideoLevel;
switch( pC->pInputClipCtxt->pSettings->ClipProperties.VideoStreamType )
{
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;
}
/* Add a link to video dsi */
if( M4SYS_kH264 == pC->ewc.VideoStreamType )
{
/* For H.264 encoder case
* Fetch the DSI from the shell video encoder, and feed it to the writer */
M4OSA_TRACE3_0("M4VSS3GPP_intAudioMixingOpen: get DSI for H264 stream");
if( M4OSA_NULL == pC->ewc.pEncContext )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen: pC->ewc.pEncContext is NULL");
err = M4VSS3GPP_intAudioMixingCreateVideoEncoder(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen:\
M4VSS3GPP_intAudioMixingCreateVideoEncoder 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_intAudioMixingOpen: failed to get the encoder header (err 0x%x)",
err);
M4OSA_TRACE1_2(
"M4VSS3GPP_intAudioMixingOpen: encHeader->pBuf=0x%x, size=0x%x",
encHeader->pBuf, encHeader->Size);
}
else
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen: send DSI for H264 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_intAudioMixingOpen():\
unable to allocate pVideoOutputDsi (H264), 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_intAudioMixingDestroyVideoEncoder(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen:\
M4VSS3GPP_intAudioMixingDestroyVideoEncoder returned error 0x%x",
err);
}
}
else
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen: pC->ewc.pEncContext is NULL, cannot get the DSI");
}
}
else
{
M4OSA_TRACE3_1(
"M4VSS3GPP_intAudioMixingOpen: input clip video stream type = 0x%x",
pC->ewc.VideoStreamType);
pC->ewc.uiVideoOutputDsiSize =
(M4OSA_UInt16)pC->pInputClipCtxt->pVideoStream->
m_basicProperties.m_decoderSpecificInfoSize;
pC->ewc.pVideoOutputDsi = (M4OSA_MemAddr8)pC->pInputClipCtxt->pVideoStream->
m_basicProperties.m_pDecoderSpecificInfo;
}
/**
* Copy the audio properties of the added clip to the output properties */
if( pC->bHasAudio )
{
if( pC->bRemoveOriginal == M4OSA_TRUE )
{
pC->ewc.uiNbChannels =
pC->pAddedClipCtxt->pSettings->ClipProperties.uiNbChannels;
pC->ewc.uiAudioBitrate =
pC->pAddedClipCtxt->pSettings->ClipProperties.uiAudioBitrate;
pC->ewc.uiSamplingFrequency = pC->pAddedClipCtxt->pSettings->
ClipProperties.uiSamplingFrequency;
pC->ewc.uiSilencePcmSize =
pC->pAddedClipCtxt->pSettings->ClipProperties.uiDecodedPcmSize;
pC->ewc.scale_audio = pC->ewc.uiSamplingFrequency / 1000.0;
/* if output settings are differents from added clip settings,
we need to reencode BGM */
if( pC->pAddedClipCtxt->pSettings->ClipProperties.AudioStreamType
!= pSettings->outputAudioFormat
|| pC->pAddedClipCtxt->pSettings->
ClipProperties.uiSamplingFrequency != outputASF
|| pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels
!= pSettings->outputNBChannels
|| pC->pAddedClipCtxt->pSettings->
ClipProperties.AudioStreamType == M4VIDEOEDITING_kMP3 )
{
/* Set reader DSI to NULL (unknown), we will use encoder DSI later */
if( pC->pAddedClipCtxt->pAudioStream->
m_basicProperties.m_pDecoderSpecificInfo != M4OSA_NULL )
{
/*
free(pC->pAddedClipCtxt->pAudioStream->\
m_basicProperties.m_pDecoderSpecificInfo);
*/
pC->pAddedClipCtxt->pAudioStream->
m_basicProperties.m_decoderSpecificInfoSize = 0;
pC->pAddedClipCtxt->pAudioStream->
m_basicProperties.m_pDecoderSpecificInfo = M4OSA_NULL;
}
pC->ewc.uiNbChannels =
pC->pInputClipCtxt->pSettings->ClipProperties.uiNbChannels;
pC->ewc.uiSamplingFrequency = pC->pInputClipCtxt->pSettings->
ClipProperties.uiSamplingFrequency;
pC->ewc.scale_audio = pC->ewc.uiSamplingFrequency / 1000.0;
if( pSettings->outputAudioFormat == 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->ewc.uiAudioBitrate = 12200;
pC->ewc.uiSamplingFrequency = 8000;
pC->ewc.uiSilencePcmSize = 320;
pC->ewc.scale_audio = pC->ewc.uiSamplingFrequency / 1000.0;
}
else if( pSettings->outputAudioFormat == M4VIDEOEDITING_kAAC )
{
pC->ewc.AudioStreamType = M4SYS_kAAC;
if( pSettings->outputAudioBitrate
== M4VIDEOEDITING_kUndefinedBitrate )
{
switch( pC->ewc.uiSamplingFrequency )
{
case 16000:
pC->ewc.uiAudioBitrate =
M4VIDEOEDITING_k24_KBPS;
break;
case 22050:
case 24000:
pC->ewc.uiAudioBitrate =
M4VIDEOEDITING_k32_KBPS;
break;
case 32000:
pC->ewc.uiAudioBitrate =
M4VIDEOEDITING_k48_KBPS;
break;
case 44100:
case 48000:
pC->ewc.uiAudioBitrate =
M4VIDEOEDITING_k64_KBPS;
break;
default:
pC->ewc.uiAudioBitrate =
M4VIDEOEDITING_k64_KBPS;
break;
}
if( pC->ewc.uiNbChannels == 2 )
{
/* Output bitrate have to be doubled */
pC->ewc.uiAudioBitrate += pC->ewc.uiAudioBitrate;
}
}
else
{
pC->ewc.uiAudioBitrate = pSettings->outputAudioBitrate;
}
if( pC->ewc.uiNbChannels == 1 )
{
pC->ewc.pSilenceFrameData =
(M4OSA_UInt8 *)M4VSS3GPP_AAC_AU_SILENCE_MONO;
pC->ewc.uiSilenceFrameSize =
M4VSS3GPP_AAC_AU_SILENCE_MONO_SIZE;
}
else
{
pC->ewc.pSilenceFrameData =
(M4OSA_UInt8 *)M4VSS3GPP_AAC_AU_SILENCE_STEREO;
pC->ewc.uiSilenceFrameSize =
M4VSS3GPP_AAC_AU_SILENCE_STEREO_SIZE;
}
pC->ewc.iSilenceFrameDuration =
1024; /* AAC is always 1024/Freq sample duration */
}
}
else
{
switch( pC->pAddedClipCtxt->pSettings->
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;
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;
}
else
{
pC->ewc.pSilenceFrameData =
(M4OSA_UInt8 *)M4VSS3GPP_AAC_AU_SILENCE_STEREO;
pC->ewc.uiSilenceFrameSize =
M4VSS3GPP_AAC_AU_SILENCE_STEREO_SIZE;
}
pC->ewc.iSilenceFrameDuration =
1024; /* AAC is always 1024/Freq sample duration */
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;
case M4VIDEOEDITING_kPCM:
/* Set reader DSI to NULL (unknown), we will use encoder DSI later */
pC->pAddedClipCtxt->pAudioStream->
m_basicProperties.m_decoderSpecificInfoSize = 0;
pC->pAddedClipCtxt->pAudioStream->
m_basicProperties.m_pDecoderSpecificInfo =
M4OSA_NULL;
if( pC->pAddedClipCtxt->pSettings->
ClipProperties.uiSamplingFrequency == 8000 )
{
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->ewc.uiAudioBitrate = M4VIDEOEDITING_k12_2_KBPS;
}
else if( pC->pAddedClipCtxt->pSettings->
ClipProperties.uiSamplingFrequency == 16000 )
{
if( pC->ewc.uiNbChannels == 1 )
{
pC->ewc.AudioStreamType = M4SYS_kAAC;
pC->ewc.pSilenceFrameData = (M4OSA_UInt8
*)M4VSS3GPP_AAC_AU_SILENCE_MONO;
pC->ewc.uiSilenceFrameSize =
M4VSS3GPP_AAC_AU_SILENCE_MONO_SIZE;
pC->ewc.iSilenceFrameDuration =
1024; /* AAC is always 1024/Freq sample duration */
pC->ewc.uiAudioBitrate =
M4VIDEOEDITING_k32_KBPS;
}
else
{
pC->ewc.AudioStreamType = M4SYS_kAAC;
pC->ewc.pSilenceFrameData = (M4OSA_UInt8
*)M4VSS3GPP_AAC_AU_SILENCE_STEREO;
pC->ewc.uiSilenceFrameSize =
M4VSS3GPP_AAC_AU_SILENCE_STEREO_SIZE;
pC->ewc.iSilenceFrameDuration =
1024; /* AAC is always 1024/Freq sample duration */
pC->ewc.uiAudioBitrate =
M4VIDEOEDITING_k64_KBPS;
}
}
else
{
pC->ewc.AudioStreamType = M4SYS_kAudioUnknown;
}
break;
default:
pC->ewc.AudioStreamType = M4SYS_kAudioUnknown;
break;
}
}
/* Add a link to audio dsi */
pC->ewc.uiAudioOutputDsiSize =
(M4OSA_UInt16)pC->pAddedClipCtxt->pAudioStream->
m_basicProperties.m_decoderSpecificInfoSize;
pC->ewc.pAudioOutputDsi = (M4OSA_MemAddr8)pC->pAddedClipCtxt->pAudioStream->
m_basicProperties.m_pDecoderSpecificInfo;
}
else
{
pC->ewc.uiNbChannels =
pC->pInputClipCtxt->pSettings->ClipProperties.uiNbChannels;
pC->ewc.uiAudioBitrate =
pC->pInputClipCtxt->pSettings->ClipProperties.uiAudioBitrate;
pC->ewc.uiSamplingFrequency = pC->pInputClipCtxt->pSettings->
ClipProperties.uiSamplingFrequency;
pC->ewc.uiSilencePcmSize =
pC->pInputClipCtxt->pSettings->ClipProperties.uiDecodedPcmSize;
pC->ewc.scale_audio = pC->ewc.uiSamplingFrequency / 1000.0;
switch( pC->pInputClipCtxt->pSettings->
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;
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;
}
else
{
pC->ewc.pSilenceFrameData =
(M4OSA_UInt8 *)M4VSS3GPP_AAC_AU_SILENCE_STEREO;
pC->ewc.uiSilenceFrameSize =
M4VSS3GPP_AAC_AU_SILENCE_STEREO_SIZE;
}
pC->ewc.iSilenceFrameDuration =
1024; /* AAC is always 1024/Freq sample duration */
break;
default:
pC->ewc.AudioStreamType = M4SYS_kAudioUnknown;
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen: No audio track in input file.");
return M4VSS3GPP_ERR_AUDIO_CANNOT_BE_MIXED;
break;
}
/* Add a link to audio dsi */
pC->ewc.uiAudioOutputDsiSize =
(M4OSA_UInt16)pC->pInputClipCtxt->pAudioStream->
m_basicProperties.m_decoderSpecificInfoSize;
pC->ewc.pAudioOutputDsi = (M4OSA_MemAddr8)pC->pInputClipCtxt->pAudioStream->
m_basicProperties.m_pDecoderSpecificInfo;
}
}
/**
* Copy common 'silence frame stuff' to ClipContext */
pC->pInputClipCtxt->uiSilencePcmSize = pC->ewc.uiSilencePcmSize;
pC->pInputClipCtxt->pSilenceFrameData = pC->ewc.pSilenceFrameData;
pC->pInputClipCtxt->uiSilenceFrameSize = pC->ewc.uiSilenceFrameSize;
pC->pInputClipCtxt->iSilenceFrameDuration = pC->ewc.iSilenceFrameDuration;
pC->pInputClipCtxt->scale_audio = pC->ewc.scale_audio;
pC->pInputClipCtxt->iAudioFrameCts =
-pC->pInputClipCtxt->iSilenceFrameDuration; /* Reset time */
/**
* Copy common 'silence frame stuff' to ClipContext */
if( pC->bHasAudio )
{
pC->pAddedClipCtxt->uiSilencePcmSize = pC->ewc.uiSilencePcmSize;
pC->pAddedClipCtxt->pSilenceFrameData = pC->ewc.pSilenceFrameData;
pC->pAddedClipCtxt->uiSilenceFrameSize = pC->ewc.uiSilenceFrameSize;
pC->pAddedClipCtxt->iSilenceFrameDuration =
pC->ewc.iSilenceFrameDuration;
pC->pAddedClipCtxt->scale_audio = pC->ewc.scale_audio;
pC->pAddedClipCtxt->iAudioFrameCts =
-pC->pAddedClipCtxt->iSilenceFrameDuration; /* Reset time */
}
/**
* Check AddCts is lower than original clip duration */
if( ( M4OSA_NULL != pC->pInputClipCtxt->pVideoStream)
&& (pC->iAddCts > (M4OSA_Int32)pC->pInputClipCtxt->pVideoStream->
m_basicProperties.m_duration) )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen(): uiAddCts is larger than video duration,\
returning M4VSS3GPP_ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION");
return M4VSS3GPP_ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION;
}
/**
* If the audio tracks are not compatible, replace input track by silence */
if( M4OSA_FALSE == pC->pInputClipCtxt->pSettings->
ClipProperties.bAudioIsCompatibleWithMasterClip )
{
M4VSS3GPP_intClipDeleteAudioTrack(pC->pInputClipCtxt);
}
/**
* Check if audio mixing is required */
if( ( ( pC->bHasAudio) && (M4OSA_FALSE
== pC->pAddedClipCtxt->pSettings->ClipProperties.bAudioIsEditable))
|| (M4OSA_TRUE == pC->bRemoveOriginal) ) /*||
(pSettings->uiAddVolume >= 100)) */
{
pC->bAudioMixingIsNeeded = M4OSA_FALSE;
}
else
{
pC->bAudioMixingIsNeeded = M4OSA_TRUE;
}
/**
* Check if output audio can support silence frames
Trick i use bAudioIsCompatibleWithMasterClip filed to store that */
if( pC->bHasAudio )
{
pC->bSupportSilence = pC->pAddedClipCtxt->pSettings->
ClipProperties.bAudioIsCompatibleWithMasterClip;
if( M4OSA_FALSE == pC->bSupportSilence )
{
if( pC->iAddCts > 0 )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen():\
iAddCts should be set to 0 with this audio track !");
return M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK;
}
if( 0 < pC->uiEndLoop )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen():\
uiEndLoop should be set to 0 with this audio track !");
return M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK;
}
}
}
if( pC->b_DuckingNeedeed == M4OSA_FALSE)
{
/**
* Compute the factor to apply to sample to do the mixing */
pC->fAddedFactor = 0.50F;
pC->fOrigFactor = 0.50F;
}
/**
* Check if SSRC is needed */
if( M4OSA_TRUE == pC->b_SSRCneeded )
{
M4OSA_UInt32 numerator, denominator, ratio, ratioBuffer;
/**
* Init the SSRC module */
SSRC_ReturnStatus_en
ReturnStatus; /* Function return status */
LVM_INT16 NrSamplesMin =
0; /* Minimal number of samples on the input or on the output */
LVM_INT32
ScratchSize; /* The size of the scratch memory */
LVM_INT16
*pInputInScratch; /* Pointer to input in the scratch buffer */
LVM_INT16
*
pOutputInScratch; /* Pointer to the output in the scratch buffer */
SSRC_Params_t ssrcParams; /* Memory for init parameters */
switch( pC->pAddedClipCtxt->pSettings->
ClipProperties.uiSamplingFrequency )
{
case 8000:
ssrcParams.SSRC_Fs_In = LVM_FS_8000;
break;
case 11025:
ssrcParams.SSRC_Fs_In = LVM_FS_11025;
break;
case 12000:
ssrcParams.SSRC_Fs_In = LVM_FS_12000;
break;
case 16000:
ssrcParams.SSRC_Fs_In = LVM_FS_16000;
break;
case 22050:
ssrcParams.SSRC_Fs_In = LVM_FS_22050;
break;
case 24000:
ssrcParams.SSRC_Fs_In = LVM_FS_24000;
break;
case 32000:
ssrcParams.SSRC_Fs_In = LVM_FS_32000;
break;
case 44100:
ssrcParams.SSRC_Fs_In = LVM_FS_44100;
break;
case 48000:
ssrcParams.SSRC_Fs_In = LVM_FS_48000;
break;
default:
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen: invalid added clip sampling frequency (%d Hz),\
returning M4VSS3GPP_ERR_UNSUPPORTED_ADDED_AUDIO_STREAM",
pC->pAddedClipCtxt->pSettings->
ClipProperties.uiSamplingFrequency);
return M4VSS3GPP_ERR_UNSUPPORTED_ADDED_AUDIO_STREAM;
}
if( 1 == pC->pAddedClipCtxt->pSettings->ClipProperties.uiNbChannels )
{
ssrcParams.SSRC_NrOfChannels = LVM_MONO;
}
else
{
ssrcParams.SSRC_NrOfChannels = LVM_STEREO;
}
switch( pC->ewc.uiSamplingFrequency )
{
case 8000:
ssrcParams.SSRC_Fs_Out = LVM_FS_8000;
break;
case 16000:
ssrcParams.SSRC_Fs_Out = LVM_FS_16000;
break;
case 22050:
ssrcParams.SSRC_Fs_Out = LVM_FS_22050;
break;
case 24000:
ssrcParams.SSRC_Fs_Out = LVM_FS_24000;
break;
case 32000:
ssrcParams.SSRC_Fs_Out = LVM_FS_32000;
break;
case 44100:
ssrcParams.SSRC_Fs_Out = LVM_FS_44100;
break;
case 48000:
ssrcParams.SSRC_Fs_Out = LVM_FS_48000;
break;
default:
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen: invalid output sampling frequency (%d Hz),\
returning M4VSS3GPP_ERR_AUDIO_CANNOT_BE_MIXED",
pC->ewc.uiSamplingFrequency);
return M4VSS3GPP_ERR_AUDIO_CANNOT_BE_MIXED;
break;
}
ReturnStatus = 0;
switch (ssrcParams.SSRC_Fs_In){
case LVM_FS_8000:
ssrcParams.NrSamplesIn = 320;
break;
case LVM_FS_11025:
ssrcParams.NrSamplesIn =441;
break;
case LVM_FS_12000:
ssrcParams.NrSamplesIn = 480;
break;
case LVM_FS_16000:
ssrcParams.NrSamplesIn = 640;
break;
case LVM_FS_22050:
ssrcParams.NrSamplesIn = 882;
break;
case LVM_FS_24000:
ssrcParams.NrSamplesIn = 960;
break;
case LVM_FS_32000:
ssrcParams.NrSamplesIn = 1280;
break;
case LVM_FS_44100:
ssrcParams.NrSamplesIn = 1764;
break;
case LVM_FS_48000:
ssrcParams.NrSamplesIn = 1920;
break;
default:
ReturnStatus = -1;
break;
}
switch (ssrcParams.SSRC_Fs_Out){
case LVM_FS_8000:
ssrcParams.NrSamplesOut= 320;
break;
case LVM_FS_11025:
ssrcParams.NrSamplesOut =441;
break;
case LVM_FS_12000:
ssrcParams.NrSamplesOut= 480;
break;
case LVM_FS_16000:
ssrcParams.NrSamplesOut= 640;
break;
case LVM_FS_22050:
ssrcParams.NrSamplesOut= 882;
break;
case LVM_FS_24000:
ssrcParams.NrSamplesOut= 960;
break;
case LVM_FS_32000:
ssrcParams.NrSamplesOut = 1280;
break;
case LVM_FS_44100:
ssrcParams.NrSamplesOut= 1764;
break;
case LVM_FS_48000:
ssrcParams.NrSamplesOut = 1920;
break;
default:
ReturnStatus = -1;
break;
}
if( ReturnStatus != SSRC_OK )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen:\
Error code %d returned by the SSRC_GetNrSamples function",
ReturnStatus);
return M4VSS3GPP_ERR_AUDIO_CANNOT_BE_MIXED;
}
NrSamplesMin =
(LVM_INT16)((ssrcParams.NrSamplesIn > ssrcParams.NrSamplesOut)
? ssrcParams.NrSamplesOut : ssrcParams.NrSamplesIn);
while( NrSamplesMin < M4VSS_SSRC_MINBLOCKSIZE )
{ /* Don't take blocks smaller that the minimal block size */
ssrcParams.NrSamplesIn = (LVM_INT16)(ssrcParams.NrSamplesIn << 1);
ssrcParams.NrSamplesOut = (LVM_INT16)(ssrcParams.NrSamplesOut << 1);
NrSamplesMin = (LVM_INT16)(NrSamplesMin << 1);
}
pC->iSsrcNbSamplIn = (LVM_INT16)(
ssrcParams.
NrSamplesIn); /* multiplication by NrOfChannels is done below */
pC->iSsrcNbSamplOut = (LVM_INT16)(ssrcParams.NrSamplesOut);
numerator =
pC->pAddedClipCtxt->pSettings->ClipProperties.uiSamplingFrequency
* pC->pAddedClipCtxt->pSettings->ClipProperties.uiNbChannels;
denominator =
pC->pInputClipCtxt->pSettings->ClipProperties.uiSamplingFrequency
* pC->pInputClipCtxt->pSettings->ClipProperties.uiNbChannels;
if( numerator % denominator == 0 )
{
ratioBuffer = (M4OSA_UInt32)(numerator / denominator);
}
else
{
ratioBuffer = (M4OSA_UInt32)(numerator / denominator) + 1;
}
ratio =
(M4OSA_UInt32)(( pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize
* ratioBuffer) / (pC->iSsrcNbSamplIn * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels));
if( ratio == 0 )
{
/* It means that the input size of SSRC bufferIn is bigger than the asked buffer */
pC->minimumBufferIn = pC->iSsrcNbSamplIn * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels;
}
else
{
ratio++; /* We use the immediate superior integer */
pC->minimumBufferIn = ratio * (pC->iSsrcNbSamplIn * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels);
}
/**
* Allocate buffer for the input of the SSRC */
pC->pSsrcBufferIn =
(M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(pC->minimumBufferIn
+ pC->pAddedClipCtxt->
AudioDecBufferOut.
m_bufferSize,
M4VSS3GPP, (M4OSA_Char *)"pSsrcBufferIn");
if( M4OSA_NULL == pC->pSsrcBufferIn )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen():\
unable to allocate pSsrcBufferIn, returning M4ERR_ALLOC");
return M4ERR_ALLOC;
}
pC->pPosInSsrcBufferIn = (M4OSA_MemAddr8)pC->pSsrcBufferIn;
/**
* Allocate buffer for the output of the SSRC */
/* The "3" value below should be optimized ... one day ... */
pC->pSsrcBufferOut =
(M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(3 * pC->iSsrcNbSamplOut * sizeof(short)
* pC->ewc.uiNbChannels, M4VSS3GPP, (M4OSA_Char *)"pSsrcBufferOut");
if( M4OSA_NULL == pC->pSsrcBufferOut )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen():\
unable to allocate pSsrcBufferOut, returning M4ERR_ALLOC");
return M4ERR_ALLOC;
}
pC->pPosInSsrcBufferOut = pC->pSsrcBufferOut;
/**
* Allocate temporary buffer needed in case of channel conversion */
if( pC->ChannelConversion > 0 )
{
/* The "3" value below should be optimized ... one day ... */
pC->pTempBuffer =
(M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(3 * pC->iSsrcNbSamplOut
* sizeof(short) * pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels, M4VSS3GPP, (M4OSA_Char *)"pSsrcBufferOut");
if( M4OSA_NULL == pC->pTempBuffer )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen():\
unable to allocate pTempBuffer, returning M4ERR_ALLOC");
return M4ERR_ALLOC;
}
pC->pPosInTempBuffer = pC->pTempBuffer;
}
}
else if( pC->ChannelConversion > 0 )
{
pC->minimumBufferIn =
pC->pAddedClipCtxt->AudioDecBufferOut.m_bufferSize;
/**
* Allocate buffer for the input of the SSRC */
pC->pSsrcBufferIn =
(M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(pC->minimumBufferIn
+ pC->pAddedClipCtxt->
AudioDecBufferOut.
m_bufferSize,
M4VSS3GPP, (M4OSA_Char *)"pSsrcBufferIn");
if( M4OSA_NULL == pC->pSsrcBufferIn )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen(): \
unable to allocate pSsrcBufferIn, returning M4ERR_ALLOC");
return M4ERR_ALLOC;
}
pC->pPosInSsrcBufferIn = (M4OSA_MemAddr8)pC->pSsrcBufferIn;
/**
* Allocate buffer for the output of the SSRC */
/* The "3" value below should be optimized ... one day ... */
pC->pSsrcBufferOut = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(
pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize,
M4VSS3GPP, (M4OSA_Char *)"pSsrcBufferOut");
if( M4OSA_NULL == pC->pSsrcBufferOut )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen():\
unable to allocate pSsrcBufferOut, returning M4ERR_ALLOC");
return M4ERR_ALLOC;
}
pC->pPosInSsrcBufferOut = pC->pSsrcBufferOut;
}
else if( (pC->pAddedClipCtxt->pSettings->ClipProperties.AudioStreamType == M4VIDEOEDITING_kMP3)||
(pC->pAddedClipCtxt->pSettings->ClipProperties.AudioStreamType == M4VIDEOEDITING_kPCM))
{
M4OSA_UInt32 minbuffer = 0;
if( pSettings->outputAudioFormat == M4VIDEOEDITING_kAAC )
{
pC->minimumBufferIn = 2048 * pC->ewc.uiNbChannels;
minbuffer = pC->minimumBufferIn;
}
else if( pSettings->outputAudioFormat == M4VIDEOEDITING_kAMR_NB )
{
pC->minimumBufferIn = 320;
if( pC->pAddedClipCtxt->AudioDecBufferOut.m_bufferSize > 320 )
{
minbuffer = pC->pAddedClipCtxt->AudioDecBufferOut.m_bufferSize;
}
else
{
minbuffer = pC->minimumBufferIn; /* Not really possible ...*/
}
}
else
{
M4OSA_TRACE1_0("Bad output audio format, in case of MP3 replacing");
return M4ERR_PARAMETER;
}
/**
* Allocate buffer for the input of the SSRC */
pC->pSsrcBufferIn =
(M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(2 * minbuffer, M4VSS3GPP,
(M4OSA_Char *)"pSsrcBufferIn");
if( M4OSA_NULL == pC->pSsrcBufferIn )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingOpen(): unable to allocate pSsrcBufferIn,\
returning M4ERR_ALLOC");
return M4ERR_ALLOC;
}
pC->pPosInSsrcBufferIn = (M4OSA_MemAddr8)pC->pSsrcBufferIn;
pC->pPosInSsrcBufferOut = pC->pPosInSsrcBufferIn;
pC->pSsrcBufferOut = pC->pSsrcBufferIn;
}
/**
* Check if audio encoder is needed to do audio mixing or audio resampling */
if( M4OSA_TRUE == pC->bAudioMixingIsNeeded || M4VIDEOEDITING_kPCM
== pC->pAddedClipCtxt->pSettings->ClipProperties.AudioStreamType
|| M4VIDEOEDITING_kMP3
== pC->pAddedClipCtxt->pSettings->ClipProperties.AudioStreamType
|| pC->pAddedClipCtxt->pSettings->ClipProperties.AudioStreamType
!= pSettings->outputAudioFormat
|| pC->pAddedClipCtxt->pSettings->ClipProperties.uiSamplingFrequency
!= outputASF
|| pC->pAddedClipCtxt->pSettings->ClipProperties.uiNbChannels
!= pSettings->outputNBChannels )
{
/**
* Init the audio encoder */
err = M4VSS3GPP_intCreateAudioEncoder(&pC->ewc, &pC->ShellAPI,
pC->ewc.uiAudioBitrate);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen(): M4VSS3GPP_intCreateAudioEncoder() returns 0x%x",
err);
return err;
}
/* In case of PCM, MP3 or audio replace with reencoding, use encoder DSI */
if( pC->ewc.uiAudioOutputDsiSize == 0 && (M4VIDEOEDITING_kPCM
== pC->pAddedClipCtxt->pSettings->ClipProperties.AudioStreamType
|| M4VIDEOEDITING_kMP3 == pC->pAddedClipCtxt->pSettings->
ClipProperties.AudioStreamType
|| pC->pAddedClipCtxt->pSettings->
ClipProperties.AudioStreamType
!= pSettings->outputAudioFormat
|| pC->pAddedClipCtxt->pSettings->
ClipProperties.uiSamplingFrequency != outputASF
|| pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels
!= pSettings->outputNBChannels) )
{
pC->ewc.uiAudioOutputDsiSize =
(M4OSA_UInt16)pC->ewc.pAudioEncDSI.infoSize;
pC->ewc.pAudioOutputDsi = pC->ewc.pAudioEncDSI.pInfo;
}
}
/**
* Init the output 3GPP file */
/*11/12/2008 CR3283 add the max output file size for the MMS use case in VideoArtist*/
err = M4VSS3GPP_intCreate3GPPOutputFile(&pC->ewc, &pC->ShellAPI,
pC->pOsaFileWritPtr, pSettings->pOutputClipFile,
pC->pOsaFileReadPtr, pSettings->pTemporaryFile, 0);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingOpen(): M4VSS3GPP_intCreate3GPPOutputFile() returns 0x%x",
err);
return err;
}
/**
* Return with no error */
M4OSA_TRACE3_0("M4VSS3GPP_intAudioMixingOpen(): returning M4NO_ERROR");
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_intAudioMixingWriteSilence()
* @brief Write an audio silence frame into the writer
* @note Mainly used when padding with silence
* @param pC (IN) VSS audio mixing internal context
* @return M4NO_ERROR: No error
******************************************************************************
*/
static M4OSA_ERR M4VSS3GPP_intAudioMixingWriteSilence(
M4VSS3GPP_InternalAudioMixingContext *pC )
{
M4OSA_ERR err;
err = pC->ShellAPI.pWriterDataFcts->pStartAU(pC->ewc.p3gpWriterContext,
M4VSS3GPP_WRITER_AUDIO_STREAM_ID, &pC->ewc.WriterAudioAU);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1("M4VSS3GPP_intAudioMixingWriteSilence:\
pWriterDataFcts->pStartAU(audio) returns 0x%x!", err);
return err;
}
M4OSA_TRACE2_0("A #### silence AU");
memcpy((void *)pC->ewc.WriterAudioAU.dataAddress,
(void *)pC->ewc.pSilenceFrameData, pC->ewc.uiSilenceFrameSize);
pC->ewc.WriterAudioAU.size = pC->ewc.uiSilenceFrameSize;
pC->ewc.WriterAudioAU.CTS =
(M4OSA_Time)(pC->ewc.dATo * pC->ewc.scale_audio + 0.5);
M4OSA_TRACE2_2("B ---- write : cts = %ld [ 0x%x ]",
(M4OSA_Int32)(pC->ewc.dATo), pC->ewc.WriterAudioAU.size);
err = pC->ShellAPI.pWriterDataFcts->pProcessAU(pC->ewc.p3gpWriterContext,
M4VSS3GPP_WRITER_AUDIO_STREAM_ID, &pC->ewc.WriterAudioAU);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingWriteSilence:\
pWriterDataFcts->pProcessAU(silence) returns 0x%x!",
err);
return err;
}
pC->ewc.dATo += pC->ewc.iSilenceFrameDuration / pC->ewc.scale_audio;
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_intAudioMixingStepVideo(M4VSS3GPP_InternalAudioMixingContext *pC)
* @brief Perform one step of video.
* @note
* @param pC (IN) VSS audio mixing internal context
* @return M4NO_ERROR: No error
******************************************************************************
*/
static M4OSA_ERR M4VSS3GPP_intAudioMixingStepVideo(
M4VSS3GPP_InternalAudioMixingContext *pC )
{
M4OSA_ERR err;
M4OSA_UInt16 offset;
M4OSA_TRACE2_3(" VIDEO step : dVTo = %f state = %d offset = %ld",
pC->ewc.dOutputVidCts, pC->State, pC->pInputClipCtxt->iVoffset);
/**
* Read the input video AU */
err = pC->pInputClipCtxt->ShellAPI.m_pReaderDataIt->m_pFctGetNextAu(
pC->pInputClipCtxt->pReaderContext,
(M4_StreamHandler *)pC->pInputClipCtxt->pVideoStream,
&pC->pInputClipCtxt->VideoAU);
if( M4NO_ERROR != err )
{
M4OSA_TRACE3_1(
"M4VSS3GPP_intAudioMixingStepVideo(): m_pFctGetNextAu(video) returns 0x%x",
err);
return err;
}
M4OSA_TRACE2_3("C .... read : cts = %.0f + %ld [ 0x%x ]",
pC->pInputClipCtxt->VideoAU.m_CTS, pC->pInputClipCtxt->iVoffset,
pC->pInputClipCtxt->VideoAU.m_size);
/**
* Get the output AU to write into */
err = pC->ShellAPI.pWriterDataFcts->pStartAU(pC->ewc.p3gpWriterContext,
M4VSS3GPP_WRITER_VIDEO_STREAM_ID, &pC->ewc.WriterVideoAU);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepVideo: pWriterDataFcts->pStartAU(Video) returns 0x%x!",
err);
return err;
}
offset = 0;
/* for h.264 stream do not read the 1st 4 bytes as they are header indicators */
if( pC->pInputClipCtxt->pVideoStream->m_basicProperties.m_streamType
== M4DA_StreamTypeVideoMpeg4Avc )
{
M4OSA_TRACE3_0(
"M4VSS3GPP_intAudioMixingStepVideo(): input stream type H264");
offset = 4;
}
pC->pInputClipCtxt->VideoAU.m_size -= offset;
/**
* Check that the video AU is not larger than expected */
if( pC->pInputClipCtxt->VideoAU.m_size > pC->ewc.uiVideoMaxAuSize )
{
M4OSA_TRACE1_2(
"M4VSS3GPP_intAudioMixingStepVideo: AU size greater than MaxAuSize (%d>%d)!\
returning M4VSS3GPP_ERR_INPUT_VIDEO_AU_TOO_LARGE",
pC->pInputClipCtxt->VideoAU.m_size, pC->ewc.uiVideoMaxAuSize);
return M4VSS3GPP_ERR_INPUT_VIDEO_AU_TOO_LARGE;
}
/**
* Copy the input AU payload to the output AU */
memcpy((void *)pC->ewc.WriterVideoAU.dataAddress,
(void *)(pC->pInputClipCtxt->VideoAU.m_dataAddress + offset),
(pC->pInputClipCtxt->VideoAU.m_size));
/**
* Copy the input AU parameters to the output AU */
pC->ewc.WriterVideoAU.size = pC->pInputClipCtxt->VideoAU.m_size;
pC->ewc.WriterVideoAU.CTS =
(M4OSA_UInt32)(pC->pInputClipCtxt->VideoAU.m_CTS + 0.5);
pC->ewc.WriterVideoAU.attribute = pC->pInputClipCtxt->VideoAU.m_attribute;
/**
* Write the AU */
M4OSA_TRACE2_2("D ---- write : cts = %lu [ 0x%x ]",
pC->ewc.WriterVideoAU.CTS, pC->ewc.WriterVideoAU.size);
err = pC->ShellAPI.pWriterDataFcts->pProcessAU(pC->ewc.p3gpWriterContext,
M4VSS3GPP_WRITER_VIDEO_STREAM_ID, &pC->ewc.WriterVideoAU);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepVideo: pWriterDataFcts->pProcessAU(Video) returns 0x%x!",
err);
return err;
}
/**
* Return with no error */
M4OSA_TRACE3_0("M4VSS3GPP_intAudioMixingStepVideo(): returning M4NO_ERROR");
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_intAudioMixingStepAudioMix(M4VSS3GPP_InternalAudioMixingContext *pC)
* @brief Perform one step of audio.
* @note
* @param pC (IN) VSS audio mixing internal context
* @return M4NO_ERROR: No error
******************************************************************************
*/
static M4OSA_ERR M4VSS3GPP_intAudioMixingStepAudioMix(
M4VSS3GPP_InternalAudioMixingContext *pC )
{
M4OSA_ERR err;
M4OSA_TRACE2_3(" AUDIO mix : dATo = %f state = %d offset = %ld",
pC->ewc.dATo, pC->State, pC->pInputClipCtxt->iAoffset);
switch( pC->State )
{
/**********************************************************/
case M4VSS3GPP_kAudioMixingState_AUDIO_FIRST_SEGMENT:
{
err = M4VSS3GPP_intAudioMixingCopyOrig(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix:\
M4VSS3GPP_intAudioMixingCopyOrig(1) returns 0x%x!",
err);
return err;
}
/**
* Check if we reached the AddCts */
if( pC->ewc.dATo >= pC->iAddCts )
{
/**
* First segment is over, state transition to second and return OK */
pC->State = M4VSS3GPP_kAudioMixingState_AUDIO_SECOND_SEGMENT;
/* Transition from reading state to encoding state */
err = M4VSS3GPP_intAudioMixingTransition(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix(): pre-encode fails err = 0x%x",
err);
return err;
}
/**
* Return with no error so the step function will be called again */
pC->pAddedClipCtxt->iAoffset =
(M4OSA_Int32)(pC->ewc.dATo * pC->ewc.scale_audio + 0.5);
M4OSA_TRACE2_0(
"M4VSS3GPP_intAudioMixingStepAudioMix(): returning M4NO_ERROR (1->2)");
return M4NO_ERROR;
}
}
break;
/**********************************************************/
case M4VSS3GPP_kAudioMixingState_AUDIO_SECOND_SEGMENT:
{
if( M4OSA_TRUE == pC->bAudioMixingIsNeeded ) /**< Mix */
{
/**
* Read the added audio AU */
if( pC->ChannelConversion > 0 || pC->b_SSRCneeded == M4OSA_TRUE
|| pC->pAddedClipCtxt->pSettings->
ClipProperties.AudioStreamType == M4VIDEOEDITING_kMP3 )
{
/* In case of sampling freq conversion and/or channel conversion,
the read next AU will be called by the
M4VSS3GPP_intAudioMixingDoMixing function */
}
else
{
err =
M4VSS3GPP_intClipReadNextAudioFrame(pC->pAddedClipCtxt);
M4OSA_TRACE2_3("E .... read : cts = %.0f + %.0f [ 0x%x ]",
pC->pAddedClipCtxt->iAudioFrameCts
/ pC->pAddedClipCtxt->scale_audio,
pC->pAddedClipCtxt->iAoffset
/ pC->pAddedClipCtxt->scale_audio,
pC->pAddedClipCtxt->uiAudioFrameSize);
if( M4WAR_NO_MORE_AU == err )
{
/**
* Decide what to do when audio is over */
if( pC->uiEndLoop > 0 )
{
/**
* Jump at the Begin loop time */
M4OSA_Int32 time = (M4OSA_Int32)(pC->uiBeginLoop);
err = pC->pAddedClipCtxt->ShellAPI.m_pReader->
m_pFctJump(
pC->pAddedClipCtxt->pReaderContext,
(M4_StreamHandler
*)pC->pAddedClipCtxt->pAudioStream,
&time);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
m_pReader->m_pFctJump(audio returns 0x%x",
err);
return err;
}
}
else
{
/* Transition from encoding state to reading state */
err = M4VSS3GPP_intAudioMixingTransition(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
pre-encode fails err = 0x%x",
err);
return err;
}
/**
* Second segment is over, state transition to third and
return OK */
pC->State =
M4VSS3GPP_kAudioMixingState_AUDIO_THIRD_SEGMENT;
/**
* Return with no error so the step function will be
called again */
M4OSA_TRACE2_0(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
returning M4NO_ERROR (2->3) a");
return M4NO_ERROR;
}
}
else if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
m_pFctGetNextAu(audio) returns 0x%x",
err);
return err;
}
}
/**
* Read the original audio AU */
err = M4VSS3GPP_intClipReadNextAudioFrame(pC->pInputClipCtxt);
M4OSA_TRACE2_3("F .... read : cts = %.0f + %.0f [ 0x%x ]",
pC->pInputClipCtxt->iAudioFrameCts
/ pC->pInputClipCtxt->scale_audio,
pC->pInputClipCtxt->iAoffset
/ pC->pInputClipCtxt->scale_audio,
pC->pInputClipCtxt->uiAudioFrameSize);
if( M4NO_ERROR != err )
{
M4OSA_TRACE3_1(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
m_pFctGetNextAu(audio) returns 0x%x",
err);
return err;
}
if( pC->ChannelConversion == 0
&& pC->b_SSRCneeded == M4OSA_FALSE
&& pC->pAddedClipCtxt->pSettings->
ClipProperties.AudioStreamType != M4VIDEOEDITING_kMP3 )
{
/**
* 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_intAudioMixingStepAudioMix:\
pWriterDataFcts->pStartAU(audio) returns 0x%x!",
err);
return err;
}
}
/**
* Perform the audio mixing */
err = M4VSS3GPP_intAudioMixingDoMixing(pC);
if( err == M4VSS3GPP_WAR_END_OF_ADDED_AUDIO )
{
return M4NO_ERROR;
}
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix:\
M4VSS3GPP_intAudioMixingDoMixing returns 0x%x!",
err);
return err;
}
}
else /**< No mix, just copy added audio */
{
err = M4VSS3GPP_intAudioMixingCopyAdded(pC);
if( M4WAR_NO_MORE_AU == err )
{
/**
* Decide what to do when audio is over */
if( pC->uiEndLoop > 0 )
{
/**
* Jump at the Begin loop time */
M4OSA_Int32 time = (M4OSA_Int32)(pC->uiBeginLoop);
err =
pC->pAddedClipCtxt->ShellAPI.m_pReader->m_pFctJump(
pC->pAddedClipCtxt->pReaderContext,
(M4_StreamHandler
*)pC->pAddedClipCtxt->pAudioStream,
&time);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
m_pReader->m_pFctJump(audio returns 0x%x",
err);
return err;
}
/**
* 'BZZZ' bug fix:
* add a silence frame */
err = M4VSS3GPP_intAudioMixingWriteSilence(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
M4VSS3GPP_intAudioMixingWriteSilence returns 0x%x",
err);
return err;
}
/**
* Return with no error so the step function will be called again to
read audio data */
pC->pAddedClipCtxt->iAoffset =
(M4OSA_Int32)(pC->ewc.dATo * pC->ewc.scale_audio
+ 0.5);
M4OSA_TRACE2_0(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
returning M4NO_ERROR (loop)");
return M4NO_ERROR;
}
else
{
/* Transition to begin cut */
err = M4VSS3GPP_intAudioMixingTransition(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
pre-encode fails err = 0x%x",
err);
return err;
}
/**
* Second segment is over, state transition to third */
pC->State =
M4VSS3GPP_kAudioMixingState_AUDIO_THIRD_SEGMENT;
/**
* Return with no error so the step function will be called again */
M4OSA_TRACE2_0(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
returning M4NO_ERROR (2->3) b");
return M4NO_ERROR;
}
}
else if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
M4VSS3GPP_intAudioMixingCopyOrig(2) returns 0x%x",
err);
return err;
}
}
/**
* Check if we reached the end of the video */
if( pC->ewc.dATo >= pC->ewc.iOutputDuration )
{
M4OSA_TRACE3_0(
"M4VSS3GPP_intAudioMixingStepAudioMix(): Video duration reached,\
returning M4WAR_NO_MORE_AU");
return M4WAR_NO_MORE_AU; /**< Simulate end of file error */
}
}
break;
/**********************************************************/
case M4VSS3GPP_kAudioMixingState_AUDIO_THIRD_SEGMENT:
{
err = M4VSS3GPP_intAudioMixingCopyOrig(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix:\
M4VSS3GPP_intAudioMixingCopyOrig(3) returns 0x%x!",
err);
return err;
}
/**
* Check if we reached the end of the video */
if( pC->ewc.dATo >= pC->ewc.iOutputDuration )
{
M4OSA_TRACE3_0(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
Video duration reached, returning M4WAR_NO_MORE_AU");
return M4WAR_NO_MORE_AU; /**< Simulate end of file error */
}
}
break;
default:
break;
}
/**
* Return with no error */
M4OSA_TRACE3_0(
"M4VSS3GPP_intAudioMixingStepAudioMix(): returning M4NO_ERROR");
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_intAudioMixingStepAudioReplace(M4VSS3GPP_InternalAudioMixingContext *pC)
* @brief Perform one step of audio.
* @note
* @param pC (IN) VSS audio mixing internal context
* @return M4NO_ERROR: No error
******************************************************************************
*/
static M4OSA_ERR M4VSS3GPP_intAudioMixingStepAudioReplace(
M4VSS3GPP_InternalAudioMixingContext *pC )
{
M4OSA_ERR err;
M4OSA_TRACE2_3(" AUDIO repl : dATo = %f state = %d offset = %ld",
pC->ewc.dATo, pC->State, pC->pInputClipCtxt->iAoffset);
switch( pC->State )
{
/**********************************************************/
case M4VSS3GPP_kAudioMixingState_AUDIO_FIRST_SEGMENT:
{
/**
* Replace the SID (silence) payload in the writer AU */
err = M4VSS3GPP_intAudioMixingWriteSilence(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
M4VSS3GPP_intAudioMixingWriteSilence returns 0x%x",
err);
return err;
}
/**
* Check if we reached the AddCts */
if( pC->ewc.dATo >= pC->iAddCts )
{
/**
* First segment is over, state transition to second and return OK */
pC->State = M4VSS3GPP_kAudioMixingState_AUDIO_SECOND_SEGMENT;
/**
* Return with no error so the step function will be called again */
pC->pAddedClipCtxt->iAoffset =
(M4OSA_Int32)(pC->ewc.dATo * pC->ewc.scale_audio + 0.5);
M4OSA_TRACE2_0("M4VSS3GPP_intAudioMixingStepAudioReplace():\
returning M4NO_ERROR (1->2)");
return M4NO_ERROR;
}
}
break;
/**********************************************************/
case M4VSS3GPP_kAudioMixingState_AUDIO_SECOND_SEGMENT:
{
err = M4VSS3GPP_intAudioMixingCopyAdded(pC);
if( M4WAR_NO_MORE_AU == err )
{
/**
* Decide what to do when audio is over */
if( pC->uiEndLoop > 0 )
{
/**
* Jump at the Begin loop time */
M4OSA_Int32 time = (M4OSA_Int32)(pC->uiBeginLoop);
err = pC->pAddedClipCtxt->ShellAPI.m_pReader->m_pFctJump(
pC->pAddedClipCtxt->pReaderContext,
(M4_StreamHandler
*)pC->pAddedClipCtxt->pAudioStream, &time);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioReplace():\
m_pReader->m_pFctJump(audio returns 0x%x",
err);
return err;
}
/**
* 'BZZZ' bug fix:
* add a silence frame */
err = M4VSS3GPP_intAudioMixingWriteSilence(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
M4VSS3GPP_intAudioMixingWriteSilence returns 0x%x",
err);
return err;
}
/**
* Return with no error so the step function will be called again to
read audio data */
pC->pAddedClipCtxt->iAoffset =
(M4OSA_Int32)(pC->ewc.dATo * pC->ewc.scale_audio + 0.5);
M4OSA_TRACE2_0(
"M4VSS3GPP_intAudioMixingStepAudioReplace():\
returning M4NO_ERROR (loop)");
return M4NO_ERROR;
}
else if( M4OSA_TRUE == pC->bSupportSilence )
{
/**
* Second segment is over, state transition to third and return OK */
pC->State = M4VSS3GPP_kAudioMixingState_AUDIO_THIRD_SEGMENT;
/**
* Return with no error so the step function will be called again */
M4OSA_TRACE2_0(
"M4VSS3GPP_intAudioMixingStepAudioReplace():\
returning M4NO_ERROR (2->3)");
return M4NO_ERROR;
}
else
{
/**
* The third segment (silence) is only done if supported.
* In other case, we finish here. */
pC->State = M4VSS3GPP_kAudioMixingState_FINISHED;
/**
* Return with no error so the step function will be called again */
M4OSA_TRACE2_0(
"M4VSS3GPP_intAudioMixingStepAudioReplace():\
returning M4NO_ERROR (2->F)");
return M4NO_ERROR;
}
}
else if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioReplace():\
M4VSS3GPP_intAudioMixingCopyOrig(2) returns 0x%x",
err);
return err;
}
/**
* Check if we reached the end of the clip */
if( pC->ewc.dATo >= pC->ewc.iOutputDuration )
{
M4OSA_TRACE3_0(
"M4VSS3GPP_intAudioMixingStepAudioReplace(): Clip duration reached,\
returning M4WAR_NO_MORE_AU");
return M4WAR_NO_MORE_AU; /**< Simulate end of file error */
}
}
break;
/**********************************************************/
case M4VSS3GPP_kAudioMixingState_AUDIO_THIRD_SEGMENT:
{
/**
* Replace the SID (silence) payload in the writer AU */
err = M4VSS3GPP_intAudioMixingWriteSilence(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix():\
M4VSS3GPP_intAudioMixingWriteSilence returns 0x%x",
err);
return err;
}
/**
* Check if we reached the end of the video */
if( pC->ewc.dATo >= pC->ewc.iOutputDuration )
{
M4OSA_TRACE3_0(
"M4VSS3GPP_intAudioMixingStepAudioReplace():\
Video duration reached, returning M4WAR_NO_MORE_AU");
return M4WAR_NO_MORE_AU; /**< Simulate end of file error */
}
}
break;
default:
break;
}
/**
* Return with no error */
M4OSA_TRACE3_0(
"M4VSS3GPP_intAudioMixingStepAudioReplace(): returning M4NO_ERROR");
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_intAudioMixingCopyOrig(M4VSS3GPP_InternalAudioMixingContext *pC)
* @brief Read one AU from the original audio file and write it to the output
* @note
* @param pC (IN) VSS audio mixing internal context
******************************************************************************
*/
static M4OSA_ERR M4VSS3GPP_intAudioMixingCopyOrig(
M4VSS3GPP_InternalAudioMixingContext *pC )
{
M4OSA_ERR err;
/**
* Read the input original audio AU */
err = M4VSS3GPP_intClipReadNextAudioFrame(pC->pInputClipCtxt);
M4OSA_TRACE2_3("G .... read : cts = %.0f + %.0f [ 0x%x ]",
pC->pInputClipCtxt->iAudioFrameCts / pC->pInputClipCtxt->scale_audio,
pC->pInputClipCtxt->iAoffset / pC->pInputClipCtxt->scale_audio,
pC->pInputClipCtxt->uiAudioFrameSize);
if( M4NO_ERROR != err )
{
M4OSA_TRACE3_1(
"M4VSS3GPP_intAudioMixingCopyOrig(): m_pFctGetNextAu(audio) returns 0x%x",
err);
return err;
}
/**
* 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_intAudioMixingCopyOrig: pWriterDataFcts->pStartAU(audio) returns 0x%x!",
err);
return err;
}
/**
* Copy the input AU properties to the output AU */
pC->ewc.WriterAudioAU.size = pC->pInputClipCtxt->uiAudioFrameSize;
pC->ewc.WriterAudioAU.CTS =
pC->pInputClipCtxt->iAudioFrameCts + pC->pInputClipCtxt->iAoffset;
/**
* Copy the AU itself */
memcpy((void *)pC->ewc.WriterAudioAU.dataAddress,
(void *)pC->pInputClipCtxt->pAudioFramePtr, pC->ewc.WriterAudioAU.size);
/**
* Write the mixed AU */
M4OSA_TRACE2_2("H ---- write : cts = %ld [ 0x%x ]",
(M4OSA_Int32)(pC->ewc.WriterAudioAU.CTS / pC->ewc.scale_audio),
pC->ewc.WriterAudioAU.size);
err = pC->ShellAPI.pWriterDataFcts->pProcessAU(pC->ewc.p3gpWriterContext,
M4VSS3GPP_WRITER_AUDIO_STREAM_ID, &pC->ewc.WriterAudioAU);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingCopyOrig: pWriterDataFcts->pProcessAU(audio) returns 0x%x!",
err);
return err;
}
/**
* Increment the audio CTS for the next step */
pC->ewc.dATo += pC->ewc.iSilenceFrameDuration / pC->ewc.scale_audio;
/**
* Return with no error */
M4OSA_TRACE3_0("M4VSS3GPP_intAudioMixingCopyOrig(): returning M4NO_ERROR");
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_intAudioMixingCopyAdded(M4VSS3GPP_InternalAudioMixingContext *pC)
* @brief Read one AU from the added audio file and write it to the output
* @note
* @param pC (IN) VSS audio mixing internal context
******************************************************************************
*/
static M4OSA_ERR M4VSS3GPP_intAudioMixingCopyAdded(
M4VSS3GPP_InternalAudioMixingContext *pC )
{
M4OSA_ERR err;
if(pC->pAddedClipCtxt->pSettings->ClipProperties.AudioStreamType == M4VIDEOEDITING_kMP3 ||
pC->pAddedClipCtxt->pSettings->ClipProperties.AudioStreamType == M4VIDEOEDITING_kPCM ||
pC->b_SSRCneeded == M4OSA_TRUE ||
pC->ChannelConversion > 0)
{
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_MemAddr8 tempPosBuffer;
err = M4VSS3GPP_intAudioMixingConvert(pC);
if( err == M4VSS3GPP_WAR_END_OF_ADDED_AUDIO )
{
M4OSA_TRACE2_0(
"M4VSS3GPP_intAudioMixingCopyAdded:\
M4VSS3GPP_intAudioMixingConvert end of added file");
return M4NO_ERROR;
}
else if( err != M4NO_ERROR )
{
M4OSA_TRACE1_1("M4VSS3GPP_intAudioMixingCopyAdded:\
M4VSS3GPP_intAudioMixingConvert returned 0x%x", err);
return err;
}
/**
* 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_intAudioMixingStepAudioMix:\
pWriterDataFcts->pStartAU(audio) returns 0x%x!",
err);
return err;
}
/* [Mono] or [Stereo interleaved] : all is in one buffer */
pEncInBuffer.pTableBuffer[0] = pC->pSsrcBufferOut;
pEncInBuffer.pTableBufferSize[0] =
pC->pInputClipCtxt->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("K **** blend AUs");
/**
* Encode the PCM audio */
err = pC->ShellAPI.pAudioEncoderGlobalFcts->pFctStep(
pC->ewc.pAudioEncCtxt, &pEncInBuffer, &pEncOutBuffer);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingDoMixing():\
pAudioEncoderGlobalFcts->pFctStep returns 0x%x",
err);
return err;
}
/**
* Set AU cts and size */
pC->ewc.WriterAudioAU.size =
pEncOutBuffer.
pTableBufferSize[0]; /**< Get the size of encoded data */
pC->ewc.WriterAudioAU.CTS += frameTimeDelta;
/* Update decoded buffer here */
if( M4OSA_TRUE == pC->b_SSRCneeded || pC->ChannelConversion > 0 )
{
tempPosBuffer = pC->pSsrcBufferOut
+ pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize;
memmove((void *)pC->pSsrcBufferOut, (void *)tempPosBuffer,
pC->pPosInSsrcBufferOut - tempPosBuffer);
pC->pPosInSsrcBufferOut -=
pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize;
}
else
{
tempPosBuffer = pC->pSsrcBufferIn + pC->minimumBufferIn;
memmove((void *)pC->pSsrcBufferIn, (void *)tempPosBuffer,
pC->pPosInSsrcBufferIn - tempPosBuffer);
pC->pPosInSsrcBufferIn -= pC->minimumBufferIn;
}
/**
* Write the mixed AU */
M4OSA_TRACE2_2("J ---- write : cts = %ld [ 0x%x ]",
(M4OSA_Int32)(pC->ewc.WriterAudioAU.CTS / pC->ewc.scale_audio),
pC->ewc.WriterAudioAU.size);
err =
pC->ShellAPI.pWriterDataFcts->pProcessAU(pC->ewc.p3gpWriterContext,
M4VSS3GPP_WRITER_AUDIO_STREAM_ID, &pC->ewc.WriterAudioAU);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingCopyAdded:\
pWriterDataFcts->pProcessAU(audio) returns 0x%x!",
err);
return err;
}
/**
* Increment the audio CTS for the next step */
pC->ewc.dATo += frameTimeDelta / pC->ewc.scale_audio;
}
else
{
/**
* Read the added audio AU */
err = M4VSS3GPP_intClipReadNextAudioFrame(pC->pAddedClipCtxt);
M4OSA_TRACE2_3("I .... read : cts = %.0f + %.0f [ 0x%x ]",
pC->pAddedClipCtxt->iAudioFrameCts
/ pC->pAddedClipCtxt->scale_audio,
pC->pAddedClipCtxt->iAoffset / pC->pAddedClipCtxt->scale_audio,
pC->pAddedClipCtxt->uiAudioFrameSize);
if( M4NO_ERROR != err )
{
M4OSA_TRACE3_1(
"M4VSS3GPP_intAudioMixingCopyAdded(): m_pFctGetNextAu(audio) returns 0x%x",
err);
return err;
}
/**
* 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_intAudioMixingCopyAdded:\
pWriterDataFcts->pStartAU(audio) returns 0x%x!",
err);
return err;
}
/**
* Copy the input AU properties to the output AU */
/** THE CHECK BELOW IS ADDED TO PREVENT ISSUES LINKED TO PRE-ALLOCATED MAX AU SIZE
max AU size is set based on M4VSS3GPP_AUDIO_MAX_AU_SIZE defined in file
M4VSS3GPP_InternalConfig.h, If this error occurs increase the limit set in this file
*/
if( pC->pAddedClipCtxt->uiAudioFrameSize > pC->ewc.WriterAudioAU.size )
{
M4OSA_TRACE1_2(
"ERROR: audio AU size (%d) to copy larger than allocated one (%d) => abort",
pC->pAddedClipCtxt->uiAudioFrameSize,
pC->ewc.WriterAudioAU.size);
M4OSA_TRACE1_0(
"PLEASE CONTACT SUPPORT TO EXTEND MAX AU SIZE IN THE PRODUCT LIBRARY");
err = M4ERR_UNSUPPORTED_MEDIA_TYPE;
return err;
}
pC->ewc.WriterAudioAU.size = pC->pAddedClipCtxt->uiAudioFrameSize;
pC->ewc.WriterAudioAU.CTS =
pC->pAddedClipCtxt->iAudioFrameCts + pC->pAddedClipCtxt->iAoffset;
/**
* Copy the AU itself */
memcpy((void *)pC->ewc.WriterAudioAU.dataAddress,
(void *)pC->pAddedClipCtxt->pAudioFramePtr, pC->ewc.WriterAudioAU.size);
/**
* Write the mixed AU */
M4OSA_TRACE2_2("J ---- write : cts = %ld [ 0x%x ]",
(M4OSA_Int32)(pC->ewc.WriterAudioAU.CTS / pC->ewc.scale_audio),
pC->ewc.WriterAudioAU.size);
err =
pC->ShellAPI.pWriterDataFcts->pProcessAU(pC->ewc.p3gpWriterContext,
M4VSS3GPP_WRITER_AUDIO_STREAM_ID, &pC->ewc.WriterAudioAU);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingCopyAdded:\
pWriterDataFcts->pProcessAU(audio) returns 0x%x!",
err);
return err;
}
/**
* Increment the audio CTS for the next step */
pC->ewc.dATo += pC->ewc.iSilenceFrameDuration / pC->ewc.scale_audio;
}
/**
* Return with no error */
M4OSA_TRACE3_0("M4VSS3GPP_intAudioMixingCopyAdded(): returning M4NO_ERROR");
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_intAudioMixingConvert(M4VSS3GPP_InternalAudioMixingContext *pC)
* @brief Convert PCM of added track to the right ASF / nb of Channels
* @note
* @param pC (IN) VSS audio mixing internal context
* @return M4NO_ERROR: No error
******************************************************************************
*/
static M4OSA_ERR M4VSS3GPP_intAudioMixingConvert(
M4VSS3GPP_InternalAudioMixingContext *pC )
{
M4OSA_ERR err;
int ssrcErr; /**< Error while ssrc processing */
M4OSA_UInt32 uiChannelConvertorNbSamples =
pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize / sizeof(short)
/ pC->pInputClipCtxt->pSettings->ClipProperties.uiNbChannels;
M4OSA_MemAddr8 tempPosBuffer;
M4OSA_UInt32 outFrameCount = uiChannelConvertorNbSamples;
/* Do we need to feed SSRC buffer In ? */
/**
* RC: This is not really optimum (memmove). We should handle this with linked list. */
while( pC->pPosInSsrcBufferIn - pC->pSsrcBufferIn < (M4OSA_Int32)pC->minimumBufferIn )
{
/* We need to get more PCM data */
if (pC->bNoLooping == M4OSA_TRUE)
{
err = M4WAR_NO_MORE_AU;
}
else
{
err = M4VSS3GPP_intClipReadNextAudioFrame(pC->pAddedClipCtxt);
}
if(pC->bjumpflag)
{
/**
* Jump at the Begin loop time */
M4OSA_Int32 time = (M4OSA_Int32)(pC->uiBeginLoop);
err =
pC->pAddedClipCtxt->ShellAPI.m_pReader->m_pFctJump\
(pC->pAddedClipCtxt->pReaderContext,
(M4_StreamHandler*)pC->pAddedClipCtxt->pAudioStream, &time);
if (M4NO_ERROR != err)
{
M4OSA_TRACE1_1("M4VSS3GPP_intAudioMixingConvert():\
m_pReader->m_pFctJump(audio returns 0x%x", err);
return err;
}
pC->bjumpflag = M4OSA_FALSE;
}
M4OSA_TRACE2_3("E .... read : cts = %.0f + %.0f [ 0x%x ]",
pC->pAddedClipCtxt->iAudioFrameCts / pC->pAddedClipCtxt->scale_audio,
pC->pAddedClipCtxt->iAoffset / pC->pAddedClipCtxt->scale_audio,
pC->pAddedClipCtxt->uiAudioFrameSize);
if( M4WAR_NO_MORE_AU == err )
{
if(pC->bNoLooping == M4OSA_TRUE)
{
pC->uiEndLoop =0; /* Value 0 means no looping is required */
}
/**
* Decide what to do when audio is over */
if( pC->uiEndLoop > 0 )
{
/**
* Jump at the Begin loop time */
M4OSA_Int32 time = (M4OSA_Int32)(pC->uiBeginLoop);
err = pC->pAddedClipCtxt->ShellAPI.m_pReader->m_pFctJump(
pC->pAddedClipCtxt->pReaderContext,
(M4_StreamHandler *)pC->pAddedClipCtxt->
pAudioStream, &time);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingConvert():\
m_pReader->m_pFctJump(audio returns 0x%x",
err);
return err;
}
}
else
{
/* Transition from encoding state to reading state */
err = M4VSS3GPP_intAudioMixingTransition(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingStepAudioMix(): pre-encode fails err = 0x%x",
err);
return err;
}
/**
* Second segment is over, state transition to third and return OK */
pC->State = M4VSS3GPP_kAudioMixingState_AUDIO_THIRD_SEGMENT;
/**
* Return with no error so the step function will be called again */
M4OSA_TRACE2_0(
"M4VSS3GPP_intAudioMixingConvert():\
returning M4VSS3GPP_WAR_END_OF_ADDED_AUDIO (2->3) a");
return M4VSS3GPP_WAR_END_OF_ADDED_AUDIO;
}
}
else if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingConvert(): m_pFctGetNextAu(audio) returns 0x%x",
err);
return err;
}
err = M4VSS3GPP_intClipDecodeCurrentAudioFrame(pC->pAddedClipCtxt);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingDoMixing:\
M4VSS3GPP_intClipDecodeCurrentAudioFrame(added) returns 0x%x",
err);
return M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AU;
}
/* Copy decoded data into SSRC buffer in */
memcpy((void *)pC->pPosInSsrcBufferIn,
(void *)pC->pAddedClipCtxt->AudioDecBufferOut.m_dataAddress,
pC->pAddedClipCtxt->AudioDecBufferOut.m_bufferSize);
/* Update position pointer into SSRC buffer In */
pC->pPosInSsrcBufferIn +=
pC->pAddedClipCtxt->AudioDecBufferOut.m_bufferSize;
}
/* Do the resampling / channel conversion if needed (=feed buffer out) */
if( pC->b_SSRCneeded == M4OSA_TRUE )
{
pC->ChannelConversion = 0;
if( pC->ChannelConversion > 0 )
{
while( pC->pPosInTempBuffer - pC->pTempBuffer
< (M4OSA_Int32)(pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize
*pC->pAddedClipCtxt->pSettings->ClipProperties.uiNbChannels)
/ pC->ChannelConversion )
/* We use ChannelConversion variable because in case 2, we need twice less data */
{
ssrcErr = 0;
memset((void *)pC->pPosInTempBuffer,0,
(pC->iSsrcNbSamplOut * sizeof(short) * pC->ewc.uiNbChannels));
LVAudioresample_LowQuality((short*)pC->pPosInTempBuffer,
(short*)pC->pSsrcBufferIn,
pC->iSsrcNbSamplOut,
pC->pLVAudioResampler);
if( 0 != ssrcErr )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingConvert: SSRC_Process returns 0x%x, returning ",
ssrcErr);
return ssrcErr;
}
pC->pPosInTempBuffer += pC->iSsrcNbSamplOut * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels;
/* Update SSRC bufferIn */
tempPosBuffer =
pC->pSsrcBufferIn + (pC->iSsrcNbSamplIn * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels);
memmove((void *)pC->pSsrcBufferIn, (void *)tempPosBuffer,
pC->pPosInSsrcBufferIn - tempPosBuffer);
pC->pPosInSsrcBufferIn -= pC->iSsrcNbSamplIn * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels;
}
}
else
{
while( pC->pPosInSsrcBufferOut - pC->pSsrcBufferOut
< (M4OSA_Int32)pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize )
{
ssrcErr = 0;
memset((void *)pC->pPosInSsrcBufferOut,0,
(pC->iSsrcNbSamplOut * sizeof(short) * pC->ewc.uiNbChannels));
LVAudioresample_LowQuality((short*)pC->pPosInSsrcBufferOut,
(short*)pC->pSsrcBufferIn,
pC->iSsrcNbSamplOut,
pC->pLVAudioResampler);
if( 0 != ssrcErr )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingConvert: SSRC_Process returns 0x%x, returning ",
ssrcErr);
return ssrcErr;
}
pC->pPosInSsrcBufferOut +=
pC->iSsrcNbSamplOut * sizeof(short) * pC->ewc.uiNbChannels;
/* Update SSRC bufferIn */
tempPosBuffer =
pC->pSsrcBufferIn + (pC->iSsrcNbSamplIn * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels);
memmove((void *)pC->pSsrcBufferIn, (void *)tempPosBuffer,
pC->pPosInSsrcBufferIn - tempPosBuffer);
pC->pPosInSsrcBufferIn -= pC->iSsrcNbSamplIn * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels;
}
}
/* Convert Stereo<->Mono */
switch( pC->ChannelConversion )
{
case 0: /* No channel conversion */
break;
case 1: /* stereo to mono */
if( pC->pPosInSsrcBufferOut - pC->pSsrcBufferOut
< (M4OSA_Int32)pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize )
{
From2iToMono_16((short *)pC->pTempBuffer,
(short *)pC->pSsrcBufferOut,
(short)(uiChannelConvertorNbSamples));
/* Update pTempBuffer */
tempPosBuffer = pC->pTempBuffer
+ (uiChannelConvertorNbSamples * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.
uiNbChannels); /* Buffer is in bytes */
memmove((void *)pC->pTempBuffer, (void *)tempPosBuffer,
pC->pPosInTempBuffer - tempPosBuffer);
pC->pPosInTempBuffer -=
(uiChannelConvertorNbSamples * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels);
pC->pPosInSsrcBufferOut +=
pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize;
}
break;
case 2: /* mono to stereo */
if( pC->pPosInSsrcBufferOut - pC->pSsrcBufferOut
< (M4OSA_Int32)pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize )
{
MonoTo2I_16((short *)pC->pTempBuffer,
(short *)pC->pSsrcBufferOut,
(short)uiChannelConvertorNbSamples);
tempPosBuffer = pC->pTempBuffer
+ (uiChannelConvertorNbSamples * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels);
memmove((void *)pC->pTempBuffer, (void *)tempPosBuffer,
pC->pPosInTempBuffer - tempPosBuffer);
pC->pPosInTempBuffer -=
(uiChannelConvertorNbSamples * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels);
pC->pPosInSsrcBufferOut +=
pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize;
}
break;
}
}
else if( pC->ChannelConversion > 0 )
{
//M4OSA_UInt32 uiChannelConvertorNbSamples =
// pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize / sizeof(short) /
// pC->pInputClipCtxt->pSettings->ClipProperties.uiNbChannels;
/* Convert Stereo<->Mono */
switch( pC->ChannelConversion )
{
case 0: /* No channel conversion */
break;
case 1: /* stereo to mono */
if( pC->pPosInSsrcBufferOut - pC->pSsrcBufferOut
< (M4OSA_Int32)pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize )
{
From2iToMono_16((short *)pC->pSsrcBufferIn,
(short *)pC->pSsrcBufferOut,
(short)(uiChannelConvertorNbSamples));
/* Update pTempBuffer */
tempPosBuffer = pC->pSsrcBufferIn
+ (uiChannelConvertorNbSamples * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.
uiNbChannels); /* Buffer is in bytes */
memmove((void *)pC->pSsrcBufferIn, (void *)tempPosBuffer,
pC->pPosInSsrcBufferIn - tempPosBuffer);
pC->pPosInSsrcBufferIn -=
(uiChannelConvertorNbSamples * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels);
pC->pPosInSsrcBufferOut +=
pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize;
}
break;
case 2: /* mono to stereo */
if( pC->pPosInSsrcBufferOut - pC->pSsrcBufferOut
< (M4OSA_Int32)pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize )
{
MonoTo2I_16((short *)pC->pSsrcBufferIn,
(short *)pC->pSsrcBufferOut,
(short)uiChannelConvertorNbSamples);
tempPosBuffer = pC->pSsrcBufferIn
+ (uiChannelConvertorNbSamples * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels);
memmove((void *)pC->pSsrcBufferIn, (void *)tempPosBuffer,
pC->pPosInSsrcBufferIn - tempPosBuffer);
pC->pPosInSsrcBufferIn -=
(uiChannelConvertorNbSamples * sizeof(short)
* pC->pAddedClipCtxt->pSettings->
ClipProperties.uiNbChannels);
pC->pPosInSsrcBufferOut +=
pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize;
}
break;
}
}
else
{
/* No channel conversion nor sampl. freq. conversion needed, just buffer management */
pC->pPosInSsrcBufferOut = pC->pPosInSsrcBufferIn;
}
return M4NO_ERROR;
}
M4OSA_Int32 M4VSS3GPP_getDecibelSound( M4OSA_UInt32 value )
{
int dbSound = 1;
if( value == 0 )
return 0;
if( value > 0x4000 && value <= 0x8000 ) // 32768
dbSound = 90;
else if( value > 0x2000 && value <= 0x4000 ) // 16384
dbSound = 84;
else if( value > 0x1000 && value <= 0x2000 ) // 8192
dbSound = 78;
else if( value > 0x0800 && value <= 0x1000 ) // 4028
dbSound = 72;
else if( value > 0x0400 && value <= 0x0800 ) // 2048
dbSound = 66;
else if( value > 0x0200 && value <= 0x0400 ) // 1024
dbSound = 60;
else if( value > 0x0100 && value <= 0x0200 ) // 512
dbSound = 54;
else if( value > 0x0080 && value <= 0x0100 ) // 256
dbSound = 48;
else if( value > 0x0040 && value <= 0x0080 ) // 128
dbSound = 42;
else if( value > 0x0020 && value <= 0x0040 ) // 64
dbSound = 36;
else if( value > 0x0010 && value <= 0x0020 ) // 32
dbSound = 30;
else if( value > 0x0008 && value <= 0x0010 ) //16
dbSound = 24;
else if( value > 0x0007 && value <= 0x0008 ) //8
dbSound = 24;
else if( value > 0x0003 && value <= 0x0007 ) // 4
dbSound = 18;
else if( value > 0x0001 && value <= 0x0003 ) //2
dbSound = 12;
else if( value > 0x000 && value <= 0x0001 ) // 1
dbSound = 6;
else
dbSound = 0;
return dbSound;
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_intAudioMixingDoMixing(M4VSS3GPP_InternalAudioMixingContext *pC)
* @brief Mix the current audio AUs (decoder, mix, encode)
* @note
* @param pC (IN) VSS audio mixing internal context
* @return M4NO_ERROR: No error
******************************************************************************
*/
static M4OSA_ERR M4VSS3GPP_intAudioMixingDoMixing(
M4VSS3GPP_InternalAudioMixingContext *pC )
{
M4OSA_ERR err;
M4OSA_Int16 *pPCMdata1;
M4OSA_Int16 *pPCMdata2;
M4OSA_UInt32 uiPCMsize;
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_MemAddr8 tempPosBuffer;
/* ducking variable */
M4OSA_UInt16 loopIndex = 0;
M4OSA_Int16 *pPCM16Sample = M4OSA_NULL;
M4OSA_Int32 peakDbValue = 0;
M4OSA_Int32 previousDbValue = 0;
M4OSA_UInt32 i;
/**
* Decode original audio track AU */
err = M4VSS3GPP_intClipDecodeCurrentAudioFrame(pC->pInputClipCtxt);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingDoMixing:\
M4VSS3GPP_intClipDecodeCurrentAudioFrame(orig) returns 0x%x",
err);
return M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AU;
}
if( M4OSA_TRUE == pC->b_SSRCneeded || pC->ChannelConversion > 0
|| pC->pAddedClipCtxt->pSettings->ClipProperties.AudioStreamType
== M4VIDEOEDITING_kMP3 )
{
err = M4VSS3GPP_intAudioMixingConvert(pC);
if( err == M4VSS3GPP_WAR_END_OF_ADDED_AUDIO )
{
return err;
}
if( err != M4NO_ERROR )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingDoMixing: M4VSS3GPP_intAudioMixingConvert returned 0x%x",
err);
return M4VSS3GPP_ERR_AUDIO_DECODED_PCM_SIZE_ISSUE;
}
/**
* 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_intAudioMixingStepAudioMix:\
pWriterDataFcts->pStartAU(audio) returns 0x%x!",
err);
return err;
}
pPCMdata2 = (M4OSA_Int16 *)pC->pSsrcBufferOut;
}
else
{
/**
* Decode added audio track AU */
err = M4VSS3GPP_intClipDecodeCurrentAudioFrame(pC->pAddedClipCtxt);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingDoMixing:\
M4VSS3GPP_intClipDecodeCurrentAudioFrame(added) returns 0x%x",
err);
return M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AU;
}
/**
* Check both clips decoded the same amount of PCM samples */
if( pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize
!= pC->pAddedClipCtxt->AudioDecBufferOut.m_bufferSize )
{
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingDoMixing:\
both clips AU must have the same decoded PCM size!");
return M4VSS3GPP_ERR_AUDIO_DECODED_PCM_SIZE_ISSUE;
}
pPCMdata2 = (M4OSA_Int16 *)pC->pAddedClipCtxt->AudioDecBufferOut.m_dataAddress;
}
/**
* Mix the two decoded PCM audios */
pPCMdata1 =
(M4OSA_Int16 *)pC->pInputClipCtxt->AudioDecBufferOut.m_dataAddress;
uiPCMsize = pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize
/ 2; /*buffer size (bytes) to number of sample (int16)*/
if( pC->b_DuckingNeedeed )
{
loopIndex = 0;
peakDbValue = 0;
previousDbValue = peakDbValue;
pPCM16Sample = (M4OSA_Int16 *)pC->pInputClipCtxt->
AudioDecBufferOut.m_dataAddress;
//Calculate the peak value
while( loopIndex
< pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize
/ sizeof(M4OSA_Int16) )
{
if( pPCM16Sample[loopIndex] >= 0 )
{
peakDbValue = previousDbValue > pPCM16Sample[loopIndex]
? previousDbValue : pPCM16Sample[loopIndex];
previousDbValue = peakDbValue;
}
else
{
peakDbValue = previousDbValue > -pPCM16Sample[loopIndex]
? previousDbValue : -pPCM16Sample[loopIndex];
previousDbValue = peakDbValue;
}
loopIndex++;
}
pC->audioVolumeArray[pC->audVolArrIndex] =
M4VSS3GPP_getDecibelSound(peakDbValue);
/* WINDOW_SIZE is 10 by default and check for threshold is done after 10 cycles */
if( pC->audVolArrIndex >= WINDOW_SIZE - 1 )
{
pC->bDoDucking =
M4VSS3GPP_isThresholdBreached((M4OSA_Int32 *)&(pC->audioVolumeArray),
pC->audVolArrIndex, pC->InDucking_threshold);
pC->audVolArrIndex = 0;
}
else
{
pC->audVolArrIndex++;
}
/*
*Below logic controls the mixing weightage for Background Track and Primary Track
*for the duration of window under analysis to give fade-out for Background and fade-in
*for primary
*
*Current fading factor is distributed in equal range over the defined window size.
*
*For a window size = 25 (500 ms (window under analysis) / 20 ms (sample duration))
*
*/
if( pC->bDoDucking )
{
if( pC->duckingFactor
> pC->InDucking_lowVolume ) // FADE OUT BG Track
{
// decrement ducking factor in total steps in factor of low volume steps to reach
// low volume level
pC->duckingFactor -= (pC->InDucking_lowVolume);
}
else
{
pC->duckingFactor = pC->InDucking_lowVolume;
}
}
else
{
if( pC->duckingFactor < 1.0 ) // FADE IN BG Track
{
// increment ducking factor in total steps of low volume factor to reach
// orig.volume level
pC->duckingFactor += (pC->InDucking_lowVolume);
}
else
{
pC->duckingFactor = 1.0;
}
}
/* endif - ducking_enable */
/* Mixing Logic */
while( uiPCMsize-- > 0 )
{
M4OSA_Int32 temp;
/* set vol factor for BT and PT */
*pPCMdata2 = (M4OSA_Int16)(*pPCMdata2 * pC->fBTVolLevel);
*pPCMdata1 = (M4OSA_Int16)(*pPCMdata1 * pC->fPTVolLevel);
/* mix the two samples */
*pPCMdata2 = (M4OSA_Int16)(( *pPCMdata2) * (pC->duckingFactor));
*pPCMdata1 = (M4OSA_Int16)(*pPCMdata2 / 2 + *pPCMdata1 / 2);
if( *pPCMdata1 < 0 )
{
temp = -( *pPCMdata1)
* 2; // bring to same Amplitude level as it was original
if( temp > 32767 )
{
*pPCMdata1 = -32766; // less then max allowed value
}
else
{
*pPCMdata1 = (M4OSA_Int16)(-temp);
}
}
else
{
temp = ( *pPCMdata1)
* 2; // bring to same Amplitude level as it was original
if( temp > 32768 )
{
*pPCMdata1 = 32767; // less than max allowed value
}
else
{
*pPCMdata1 = (M4OSA_Int16)temp;
}
}
pPCMdata2++;
pPCMdata1++;
}
}
else
{
while( uiPCMsize-- > 0 )
{
/* mix the two samples */
*pPCMdata1 = (M4OSA_Int16)(*pPCMdata1 * pC->fOrigFactor * pC->fPTVolLevel
+ *pPCMdata2 * pC->fAddedFactor * pC->fBTVolLevel );
pPCMdata1++;
pPCMdata2++;
}
}
/* Update pC->pSsrcBufferOut buffer */
if( M4OSA_TRUE == pC->b_SSRCneeded || pC->ChannelConversion > 0 )
{
tempPosBuffer = pC->pSsrcBufferOut
+ pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize;
memmove((void *)pC->pSsrcBufferOut, (void *)tempPosBuffer,
pC->pPosInSsrcBufferOut - tempPosBuffer);
pC->pPosInSsrcBufferOut -=
pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize;
}
else if( pC->pAddedClipCtxt->pSettings->ClipProperties.AudioStreamType
== M4VIDEOEDITING_kMP3 )
{
tempPosBuffer = pC->pSsrcBufferIn
+ pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize;
memmove((void *)pC->pSsrcBufferIn, (void *)tempPosBuffer,
pC->pPosInSsrcBufferIn - tempPosBuffer);
pC->pPosInSsrcBufferIn -=
pC->pInputClipCtxt->AudioDecBufferOut.m_bufferSize;
}
/* [Mono] or [Stereo interleaved] : all is in one buffer */
pEncInBuffer.pTableBuffer[0] =
pC->pInputClipCtxt->AudioDecBufferOut.m_dataAddress;
pEncInBuffer.pTableBufferSize[0] =
pC->pInputClipCtxt->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("K **** blend AUs");
/**
* Encode the PCM audio */
err = pC->ShellAPI.pAudioEncoderGlobalFcts->pFctStep(pC->ewc.pAudioEncCtxt,
&pEncInBuffer, &pEncOutBuffer);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingDoMixing(): pAudioEncoderGlobalFcts->pFctStep returns 0x%x",
err);
return err;
}
/**
* Set AU cts and size */
pC->ewc.WriterAudioAU.size =
pEncOutBuffer.pTableBufferSize[0]; /**< Get the size of encoded data */
pC->ewc.WriterAudioAU.CTS += frameTimeDelta;
/**
* Write the AU */
M4OSA_TRACE2_2("L ---- write : cts = %ld [ 0x%x ]",
(M4OSA_Int32)(pC->ewc.WriterAudioAU.CTS / pC->ewc.scale_audio),
pC->ewc.WriterAudioAU.size);
err = pC->ShellAPI.pWriterDataFcts->pProcessAU(pC->ewc.p3gpWriterContext,
M4VSS3GPP_WRITER_AUDIO_STREAM_ID, &pC->ewc.WriterAudioAU);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingDoMixing: pWriterDataFcts->pProcessAU returns 0x%x!",
err);
return err;
}
/**
* Increment the audio CTS for the next step */
pC->ewc.dATo += frameTimeDelta / pC->ewc.scale_audio;
/**
* Return with no error */
M4OSA_TRACE3_0("M4VSS3GPP_intAudioMixingDoMixing(): returning M4NO_ERROR");
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_intAudioMixingTransition(M4VSS3GPP_InternalAudioMixingContext *pC)
* @brief Decode/encode a few AU backward to initiate the encoder for later Mix segment.
* @note
* @param pC (IN) VSS audio mixing internal context
* @return M4NO_ERROR: No error
******************************************************************************
*/
static M4OSA_ERR M4VSS3GPP_intAudioMixingTransition(
M4VSS3GPP_InternalAudioMixingContext *pC )
{
M4OSA_ERR err;
M4ENCODER_AudioBuffer pEncInBuffer; /**< Encoder input buffer for api */
M4ENCODER_AudioBuffer pEncOutBuffer; /**< Encoder output buffer for api */
M4OSA_Time
frameTimeDelta = 0; /**< Duration of the encoded (then written) data */
M4OSA_Int32 iTargetCts, iCurrentCts;
/**
* 'BZZZ' bug fix:
* add a silence frame */
err = M4VSS3GPP_intAudioMixingWriteSilence(pC);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingTransition():\
M4VSS3GPP_intAudioMixingWriteSilence returns 0x%x",
err);
return err;
}
iCurrentCts = (M4OSA_Int32)(pC->ewc.dATo * pC->ewc.scale_audio + 0.5);
/* Do not do pre-encode step if there is no mixing (remove, 100 %, or not editable) */
if( M4OSA_FALSE == pC->bAudioMixingIsNeeded )
{
/**
* Advance in the original audio stream to reach the current time
* (We don't want iAudioCTS to be modified by the jump function,
* so we have to use a local variable). */
err = M4VSS3GPP_intClipJumpAudioAt(pC->pInputClipCtxt, &iCurrentCts);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1("M4VSS3GPP_intAudioMixingTransition:\
M4VSS3GPP_intClipJumpAudioAt() returns 0x%x!", err);
return err;
}
}
else
{
/**< don't try to pre-decode if clip is at its beginning... */
if( iCurrentCts > 0 )
{
/**
* 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_intAudioMixingTransition:\
pWriterDataFcts->pStartAU(audio) returns 0x%x!",
err);
return err;
}
/**
* Jump a few AUs backward */
iTargetCts = iCurrentCts - M4VSS3GPP_NB_AU_PREFETCH
* pC->ewc.iSilenceFrameDuration;
if( iTargetCts < 0 )
{
iTargetCts = 0; /**< Sanity check */
}
err = M4VSS3GPP_intClipJumpAudioAt(pC->pInputClipCtxt, &iTargetCts);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingTransition: DECODE_ENCODE-prefetch:\
M4VSS3GPP_intClipJumpAudioAt returns 0x%x!",
err);
return err;
}
/**
* Decode/encode up to the wanted position */
while( pC->pInputClipCtxt->iAudioFrameCts < iCurrentCts )
{
err = M4VSS3GPP_intClipReadNextAudioFrame(pC->pInputClipCtxt);
M4OSA_TRACE2_3("M .... read : cts = %.0f + %.0f [ 0x%x ]",
pC->pInputClipCtxt->iAudioFrameCts
/ pC->pInputClipCtxt->scale_audio,
pC->pInputClipCtxt->iAoffset
/ pC->pInputClipCtxt->scale_audio,
pC->pInputClipCtxt->uiAudioFrameSize);
if( M4OSA_ERR_IS_ERROR(err) )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingTransition: DECODE_ENCODE-prefetch:\
M4VSS3GPP_intClipReadNextAudioFrame(b) returns 0x%x!",
err);
return err;
}
err = M4VSS3GPP_intClipDecodeCurrentAudioFrame(
pC->pInputClipCtxt);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingTransition: DECODE_ENCODE-prefetch:\
M4VSS3GPP_intClipDecodeCurrentAudioFrame returns 0x%x!",
err);
return err;
}
/* [Mono] or [Stereo interleaved] : all is in one buffer */
pEncInBuffer.pTableBuffer[0] =
pC->pInputClipCtxt->AudioDecBufferOut.m_dataAddress;
pEncInBuffer.pTableBufferSize[0] =
pC->pInputClipCtxt->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 **** pre-encode");
/**
* Encode the PCM audio */
err = pC->ShellAPI.pAudioEncoderGlobalFcts->pFctStep(
pC->ewc.pAudioEncCtxt, &pEncInBuffer, &pEncOutBuffer);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingTransition():\
pAudioEncoderGlobalFcts->pFctStep returns 0x%x",
err);
return err;
}
}
/**
* Set AU cts and size */
pC->ewc.WriterAudioAU.size = pEncOutBuffer.pTableBufferSize[
0]; /**< Get the size of encoded data */
pC->ewc.WriterAudioAU.CTS += frameTimeDelta;
/**
* Write the AU */
M4OSA_TRACE2_2("O ---- write : cts = %ld [ 0x%x ]",
(M4OSA_Int32)(pC->ewc.WriterAudioAU.CTS / pC->ewc.scale_audio),
pC->ewc.WriterAudioAU.size);
err = pC->ShellAPI.pWriterDataFcts->pProcessAU(
pC->ewc.p3gpWriterContext, M4VSS3GPP_WRITER_AUDIO_STREAM_ID,
&pC->ewc.WriterAudioAU);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingTransition:\
pWriterDataFcts->pProcessAU returns 0x%x!", err);
return err;
}
/**
* Increment the audio CTS for the next step */
pC->ewc.dATo += pC->ewc.iSilenceFrameDuration / pC->ewc.scale_audio;
}
}
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_intAudioMixingCreateVideoEncoder()
* @brief Creates the video encoder
* @note
******************************************************************************
*/
static M4OSA_ERR M4VSS3GPP_intAudioMixingCreateVideoEncoder(
M4VSS3GPP_InternalAudioMixingContext *pC )
{
M4OSA_ERR err;
M4ENCODER_AdvancedParams EncParams;
/**
* Simulate a writer interface with our specific function */
pC->ewc.OurWriterDataInterface.pProcessAU =
M4VSS3GPP_intProcessAU; /**< This function is VSS 3GPP specific,
but it follow the writer interface */
pC->ewc.OurWriterDataInterface.pStartAU =
M4VSS3GPP_intStartAU; /**< This function is VSS 3GPP specific,
but it follow the writer interface */
pC->ewc.OurWriterDataInterface.pWriterContext =
(M4WRITER_Context)
pC; /**< We give the internal context as writer context */
/**
* Get the encoder interface, if not already done */
if( M4OSA_NULL == pC->ShellAPI.pVideoEncoderGlobalFcts )
{
err = M4VSS3GPP_setCurrentVideoEncoder(&pC->ShellAPI,
pC->ewc.VideoStreamType);
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingCreateVideoEncoder: setCurrentEncoder returns 0x%x",
err);
M4ERR_CHECK_RETURN(err);
}
/**
* Set encoder shell parameters according to VSS settings */
/* Common parameters */
EncParams.InputFormat = M4ENCODER_kIYUV420;
EncParams.FrameWidth = pC->ewc.uiVideoWidth;
EncParams.FrameHeight = pC->ewc.uiVideoHeight;
EncParams.uiTimeScale = pC->ewc.uiVideoTimeScale;
EncParams.videoProfile = pC->ewc.outputVideoProfile;
EncParams.videoLevel = pC->ewc.outputVideoLevel;
/* No strict regulation in video editor */
/* Because of the effects and transitions we should allow more flexibility */
/* Also it prevents to drop important frames
(with a bad result on sheduling and block effetcs) */
EncParams.bInternalRegulation = M4OSA_FALSE;
EncParams.FrameRate = M4ENCODER_kVARIABLE_FPS;
/**
* Other encoder settings (defaults) */
EncParams.uiHorizontalSearchRange = 0; /* use default */
EncParams.uiVerticalSearchRange = 0; /* use default */
EncParams.bErrorResilience = M4OSA_FALSE; /* no error resilience */
EncParams.uiIVopPeriod = 0; /* use default */
EncParams.uiMotionEstimationTools = 0; /* M4V_MOTION_EST_TOOLS_ALL */
EncParams.bAcPrediction = M4OSA_TRUE; /* use AC prediction */
EncParams.uiStartingQuantizerValue = 10; /* initial QP = 10 */
EncParams.bDataPartitioning = M4OSA_FALSE; /* no data partitioning */
switch( pC->ewc.VideoStreamType )
{
case M4SYS_kH263:
EncParams.Format = M4ENCODER_kH263;
EncParams.uiStartingQuantizerValue = 10;
EncParams.uiRateFactor = 1; /* default */
EncParams.bErrorResilience = M4OSA_FALSE;
EncParams.bDataPartitioning = M4OSA_FALSE;
break;
case M4SYS_kMPEG_4:
EncParams.Format = M4ENCODER_kMPEG4;
EncParams.uiStartingQuantizerValue = 8;
EncParams.uiRateFactor = 1;
if( M4OSA_FALSE == pC->ewc.bVideoDataPartitioning )
{
EncParams.bErrorResilience = M4OSA_FALSE;
EncParams.bDataPartitioning = M4OSA_FALSE;
}
else
{
EncParams.bErrorResilience = M4OSA_TRUE;
EncParams.bDataPartitioning = M4OSA_TRUE;
}
break;
case M4SYS_kH264:
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingCreateVideoEncoder: M4SYS_H264");
EncParams.Format = M4ENCODER_kH264;
EncParams.uiStartingQuantizerValue = 10;
EncParams.uiRateFactor = 1; /* default */
EncParams.bErrorResilience = M4OSA_FALSE;
EncParams.bDataPartitioning = M4OSA_FALSE;
break;
default:
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingCreateVideoEncoder: Unknown videoStreamType 0x%x",
pC->ewc.VideoStreamType);
return M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_FORMAT;
}
EncParams.Bitrate =
pC->pInputClipCtxt->pSettings->ClipProperties.uiVideoBitrate;
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingCreateVideoEncoder: calling encoder pFctInit");
/**
* Init the video encoder (advanced settings version of the encoder Open function) */
err = pC->ShellAPI.pVideoEncoderGlobalFcts->pFctInit(&pC->ewc.pEncContext,
&pC->ewc.OurWriterDataInterface, M4VSS3GPP_intVPP, pC,
pC->ShellAPI.pCurrentVideoEncoderExternalAPI,
pC->ShellAPI.pCurrentVideoEncoderUserData);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingCreateVideoEncoder:\
pVideoEncoderGlobalFcts->pFctInit returns 0x%x",
err);
return err;
}
pC->ewc.encoderState = M4VSS3GPP_kEncoderClosed;
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingCreateVideoEncoder: calling encoder pFctOpen");
M4OSA_TRACE1_2("vss: audio mix encoder open profile :%d, level %d",
EncParams.videoProfile, EncParams.videoLevel);
err = pC->ShellAPI.pVideoEncoderGlobalFcts->pFctOpen(pC->ewc.pEncContext,
&pC->ewc.WriterVideoAU, &EncParams);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingCreateVideoEncoder:\
pVideoEncoderGlobalFcts->pFctOpen returns 0x%x",
err);
return err;
}
pC->ewc.encoderState = M4VSS3GPP_kEncoderStopped;
M4OSA_TRACE1_0(
"M4VSS3GPP_intAudioMixingCreateVideoEncoder: calling encoder pFctStart");
if( M4OSA_NULL != pC->ShellAPI.pVideoEncoderGlobalFcts->pFctStart )
{
err = pC->ShellAPI.pVideoEncoderGlobalFcts->pFctStart(
pC->ewc.pEncContext);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingCreateVideoEncoder:\
pVideoEncoderGlobalFcts->pFctStart returns 0x%x",
err);
return err;
}
}
pC->ewc.encoderState = M4VSS3GPP_kEncoderRunning;
/**
* Return */
M4OSA_TRACE3_0(
"M4VSS3GPP_intAudioMixingCreateVideoEncoder: returning M4NO_ERROR");
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4VSS3GPP_intAudioMixingDestroyVideoEncoder()
* @brief Destroy the video encoder
* @note
******************************************************************************
*/
static M4OSA_ERR M4VSS3GPP_intAudioMixingDestroyVideoEncoder(
M4VSS3GPP_InternalAudioMixingContext *pC )
{
M4OSA_ERR err = M4NO_ERROR;
if( M4OSA_NULL != pC->ewc.pEncContext )
{
if( M4VSS3GPP_kEncoderRunning == pC->ewc.encoderState )
{
if( pC->ShellAPI.pVideoEncoderGlobalFcts->pFctStop != M4OSA_NULL )
{
err = pC->ShellAPI.pVideoEncoderGlobalFcts->pFctStop(
pC->ewc.pEncContext);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingDestroyVideoEncoder:\
pVideoEncoderGlobalFcts->pFctStop returns 0x%x",
err);
}
}
pC->ewc.encoderState = M4VSS3GPP_kEncoderStopped;
}
/* Has the encoder actually been opened? Don't close it if that's not the case. */
if( M4VSS3GPP_kEncoderStopped == pC->ewc.encoderState )
{
err = pC->ShellAPI.pVideoEncoderGlobalFcts->pFctClose(
pC->ewc.pEncContext);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingDestroyVideoEncoder:\
pVideoEncoderGlobalFcts->pFctClose returns 0x%x",
err);
}
pC->ewc.encoderState = M4VSS3GPP_kEncoderClosed;
}
err = pC->ShellAPI.pVideoEncoderGlobalFcts->pFctCleanup(
pC->ewc.pEncContext);
if( M4NO_ERROR != err )
{
M4OSA_TRACE1_1(
"M4VSS3GPP_intAudioMixingDestroyVideoEncoder:\
pVideoEncoderGlobalFcts->pFctCleanup returns 0x%x!",
err);
/**< We do not return the error here because we still have stuff to free */
}
pC->ewc.encoderState = M4VSS3GPP_kNoEncoder;
/**
* Reset variable */
pC->ewc.pEncContext = M4OSA_NULL;
}
M4OSA_TRACE3_1(
"M4VSS3GPP_intAudioMixingDestroyVideoEncoder: returning 0x%x", err);
return err;
}
M4OSA_Bool M4VSS3GPP_isThresholdBreached( M4OSA_Int32 *averageValue,
M4OSA_Int32 storeCount, M4OSA_Int32 thresholdValue )
{
M4OSA_Bool result = 0;
int i;
int finalValue = 0;
for ( i = 0; i < storeCount; i++ )
finalValue += averageValue[i];
finalValue = finalValue / storeCount;
if( finalValue > thresholdValue )
result = M4OSA_TRUE;
else
result = M4OSA_FALSE;
return result;
}