/* * 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 M4MCS_API.c * @brief MCS implementation (Video Compressor Service) * @note This file implements the API and the processing of the MCS ************************************************************************* **/ /** ******************************************************************** * Includes ******************************************************************** */ /** * OSAL headers */ #include "M4OSA_Memory.h" /**< OSAL memory management */ #include "M4OSA_Debug.h" /**< OSAL debug management */ /* PCM samples */ #include "VideoEditorResampler.h" /** * Decoder interface */ #include "M4DECODER_Common.h" /* Encoder interface*/ #include "M4ENCODER_common.h" /* Enable for DEBUG logging */ //#define MCS_DUMP_PCM_TO_FILE #ifdef MCS_DUMP_PCM_TO_FILE #include <stdio.h> FILE *file_au_reader = NULL; FILE *file_pcm_decoder = NULL; FILE *file_pcm_encoder = NULL; #endif /* Core headers */ #include "M4MCS_API.h" #include "M4MCS_ErrorCodes.h" #include "M4MCS_InternalTypes.h" #include "M4MCS_InternalConfig.h" #include "M4MCS_InternalFunctions.h" #ifdef M4MCS_SUPPORT_STILL_PICTURE #include "M4MCS_StillPicture.h" #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ /* Common headers (for aac) */ #include "M4_Common.h" #include "NXPSW_CompilerSwitches.h" #ifdef M4VSS_ENABLE_EXTERNAL_DECODERS #include "M4VD_EXTERNAL_Interface.h" #endif /* M4VSS_ENABLE_EXTERNAL_DECODERS */ #include "M4AIR_API.h" #include "OMX_Video.h" /* Version */ #define M4MCS_VERSION_MAJOR 3 #define M4MCS_VERSION_MINOR 4 #define M4MCS_VERSION_REVISION 3 /** ******************************************************************** * Static local functions ******************************************************************** */ static M4OSA_ERR M4MCS_intStepSet( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intPrepareVideoDecoder( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intPrepareVideoEncoder( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intPrepareAudioProcessing( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intPrepareWriter( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intPrepareAudioBeginCut( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intStepEncoding( M4MCS_InternalContext *pC, M4OSA_UInt8 *pTranscodedTime ); static M4OSA_ERR M4MCS_intStepBeginVideoJump( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intStepBeginVideoDecode( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intAudioNullEncoding( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intAudioTranscoding( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intVideoNullEncoding( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intVideoTranscoding( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intGetInputClipProperties( M4MCS_InternalContext *pContext ); static M4OSA_UInt32 M4MCS_intGetFrameSize_AMRNB( M4OSA_MemAddr8 pAudioFrame ); static M4OSA_UInt32 M4MCS_intGetFrameSize_EVRC( M4OSA_MemAddr8 pAudioFrame ); static M4OSA_ERR M4MCS_intCheckMaxFileSize( M4MCS_Context pContext ); static M4VIDEOEDITING_Bitrate M4MCS_intGetNearestBitrate( M4OSA_Int32 freebitrate, M4OSA_Int8 mode ); static M4OSA_ERR M4MCS_intCleanUp_ReadersDecoders( M4MCS_InternalContext *pC ); static M4OSA_ERR M4MCS_intReallocTemporaryAU( M4OSA_MemAddr8 *addr, M4OSA_UInt32 newSize ); static M4OSA_ERR M4MCS_intCheckAndGetCodecProperties( M4MCS_InternalContext *pC); static M4OSA_ERR M4MCS_intLimitBitratePerCodecProfileLevel( M4ENCODER_AdvancedParams* EncParams); static M4OSA_Int32 M4MCS_intLimitBitrateForH263Enc(M4OSA_Int32 profile, M4OSA_Int32 level, M4OSA_Int32 bitrate); static M4OSA_Int32 M4MCS_intLimitBitrateForMpeg4Enc(M4OSA_Int32 profile, M4OSA_Int32 level, M4OSA_Int32 bitrate); static M4OSA_Int32 M4MCS_intLimitBitrateForH264Enc(M4OSA_Int32 profile, M4OSA_Int32 level, M4OSA_Int32 bitrate); /** ********************************************************************** * External function used only by VideoEditor and that does not appear * in the API ********************************************************************** */ M4OSA_ERR M4MCS_open_normalMode( M4MCS_Context pContext, M4OSA_Void *pFileIn, M4VIDEOEDITING_FileType InputFileType, M4OSA_Void *pFileOut, M4OSA_Void *pTempFile ); /* All errors are fatal in the MCS */ #define M4ERR_CHECK_RETURN(err) if(M4NO_ERROR!=err) return err; /* A define used with SSRC 1.04 and above to avoid taking blocks smaller * that the minimal block size */ #define M4MCS_SSRC_MINBLOCKSIZE 100 static M4OSA_UChar Tab_MCS[8] = { 17, 5, 3, 3, 1, 1, 1, 1 }; M4OSA_ERR H264MCS_Getinstance( NSWAVC_MCS_t ** instance ) { NSWAVC_MCS_t *p_bs = M4OSA_NULL; M4OSA_ERR err = M4NO_ERROR; p_bs = (NSWAVC_MCS_t *)M4OSA_32bitAlignedMalloc(sizeof(NSWAVC_MCS_t), M4MCS, (M4OSA_Char *)"NSWAVC_MCS_t"); if( M4OSA_NULL == p_bs ) { M4OSA_TRACE1_0("H264MCS_Getinstance: allocation error"); return M4ERR_ALLOC; } p_bs->prev_frame_num = 0; p_bs->cur_frame_num = 0; p_bs->log2_max_frame_num_minus4 = 0; p_bs->prev_new_frame_num = 0; p_bs->is_done = 0; p_bs->is_first = 1; p_bs->m_pDecoderSpecificInfo = M4OSA_NULL; p_bs->m_decoderSpecificInfoSize = 0; p_bs->m_pEncoderSPS = M4OSA_NULL; p_bs->m_encoderSPSSize = 0; p_bs->m_pEncoderPPS = M4OSA_NULL; p_bs->m_encoderPPSSize = 0; p_bs->m_pFinalDSI = M4OSA_NULL; p_bs->m_pFinalDSISize = 0; p_bs->p_clip_sps = M4OSA_NULL; p_bs->m_encoder_SPS_Cnt = 0; p_bs->p_clip_pps = M4OSA_NULL; p_bs->m_encoder_PPS_Cnt = 0; p_bs->p_encoder_sps = M4OSA_NULL; p_bs->p_encoder_pps = M4OSA_NULL; p_bs->encoder_pps.slice_group_id = M4OSA_NULL; *instance = (NSWAVC_MCS_t *)p_bs; return err; } M4OSA_UInt32 H264MCS_getBits( ComBitStreamMCS_t *p_bs, M4OSA_UInt32 numBits ) { M4OSA_UInt32 ui32RetBits; M4OSA_UInt8 *pbs; M4OSA_Int32 bcnt; p_bs->i8BitCnt -= numBits; bcnt = p_bs->i8BitCnt; /* Measure the quantity of bits to be read in ui32TempBuff */ ui32RetBits = p_bs->ui32TempBuff >> (32 - numBits); /* Read numBits in ui32TempBuff */ p_bs->ui32TempBuff <<= numBits; p_bs->bitPos += numBits; if( bcnt > 24 ) { return (ui32RetBits); } else { /* at least one byte can be buffered in ui32TempBuff */ pbs = (M4OSA_UInt8 *)p_bs->pui8BfrPtr; if( bcnt < (int)(p_bs->numBitsInBuffer - p_bs->bitPos) ) { /* not enough remaining bits in ui32TempBuff: need to be filled */ do { /* On the fly detection of EPB byte */ if( ( *(pbs) == 0x03) && (!(( pbs[-1]) | (pbs[-2])))) //(p_bs->ui32LastTwoBytes & 0x0000FFFF) == 0) { /* EPB byte found: skip it and update bitPos accordingly */ (pbs)++; p_bs->bitPos += 8; } p_bs->ui32TempBuff |= *(pbs)++ << (24 - bcnt); bcnt += 8; } while ( bcnt <= 24 ); p_bs->pui8BfrPtr = (M4OSA_Int8 *)pbs; p_bs->i8BitCnt = bcnt; return (ui32RetBits); } } if( p_bs->bitPos <= p_bs->numBitsInBuffer ) { return (ui32RetBits); } else { return (0); } } M4OSA_Void H264MCS_flushBits( ComBitStreamMCS_t *p_bs, M4OSA_UInt32 numBits ) { M4OSA_UInt8 *pbs; M4OSA_UInt32 bcnt; p_bs->i8BitCnt -= numBits; bcnt = p_bs->i8BitCnt; p_bs->ui32TempBuff <<= numBits; p_bs->bitPos += numBits; if( bcnt > 24 ) { return; } else { /* at least one byte can be buffered in ui32TempBuff */ pbs = (M4OSA_UInt8 *)p_bs->pui8BfrPtr; if( bcnt < (p_bs->numBitsInBuffer - p_bs->bitPos) ) { /* Not enough remaining bits in ui32TempBuff: need to be filled */ do { /* On the fly detection of EPB byte */ if( ( *(pbs) == 0x03) && (!(( pbs[-1]) | (pbs[-2]))) ) { /* JC: EPB byte found: skip it and update bitPos accordingly */ (pbs)++; p_bs->bitPos += 8; } p_bs->ui32TempBuff |= *(pbs)++ << (24 - bcnt); bcnt += 8; } while ( bcnt <= 24 ); p_bs->pui8BfrPtr = (M4OSA_Int8 *)pbs; p_bs->i8BitCnt = bcnt; } } return; } M4OSA_UInt32 H264MCS_DecVLCReadExpGolombCode( ComBitStreamMCS_t *p_bs ) { M4OSA_UInt32 code, l0 = 0, l1; /* Reading 32 Bits from local cache buffer of Bitstream structure*/ code = p_bs->ui32TempBuff; /* Checking in first 3 bits*/ if( code >> 29 ) { l0 = Tab_MCS[(code >> 29)]; code = code >> (32 - l0); H264MCS_flushBits(p_bs, l0); } else { if( code ) { code <<= 3; for ( l0 = 3; code < 0x80000000; code <<= 1, l0++ ); if( l0 < 16 ) /*all useful bits are inside the 32 bits read */ { code = code >> (31 - l0); H264MCS_flushBits(p_bs, 2 * l0 + 1); } else { /* Read the useful bits in 2 parts */ l1 = ( l0 << 1) - 31; code >>= l0; H264MCS_flushBits(p_bs, 32); code = ( code << l1) | H264MCS_getBits(p_bs, l1); } } else { H264MCS_flushBits(p_bs, 32); if( H264MCS_getBits(p_bs, 1) ) { /* if number of leading 0's is 32, the only code allowed is 1 followed by 32 0's */ /*reading 32 more bits from bitstream buffer*/ code = H264MCS_getBits(p_bs, 32); if( code == 0 ) { return (code - 1); } } /*if number of leading 0's is >32, then symbol is >32 bits, which is an error */ //p_bs->state = _BS_ERR; //p_bs->flags |= _BF_SYM_ERR; return (0); } } if( 1 ) //(p_bs->state == _BS_OK) { return (code - 1); } else { return (0); } } M4OSA_Int32 H264MCS_DecVLCReadSignedExpGolombCode( ComBitStreamMCS_t *p_bs ) { M4OSA_Int32 codeNo, ret; /* read the unsigned code number */ codeNo = H264MCS_DecVLCReadExpGolombCode(p_bs); /* map to the signed value, if value is odd then it's positive, if even then it's negative, formula is (-1)^(k+1)*CEIL(k/2) */ ret = (codeNo & 0x01) ? (( codeNo + 1) >> 1) : (( -codeNo) >> 1); return ret; } M4OSA_Void DecBitStreamReset_MCS( ComBitStreamMCS_t *p_bs, M4OSA_UInt32 bytes_read ) { p_bs->bitPos = 0; p_bs->lastTotalBits = 0; p_bs->numBitsInBuffer = bytes_read << 3; p_bs->readableBytesInBuffer = bytes_read; //p_bs->state = M4NO_ERROR;//_BS_OK; //p_bs->flags = 0; p_bs->ui32TempBuff = 0; p_bs->i8BitCnt = 0; p_bs->pui8BfrPtr = (M4OSA_Int8 *)p_bs->Buffer; p_bs->ui32LastTwoBytes = 0xFFFFFFFF; H264MCS_getBits(p_bs, 0); } M4OSA_ERR NSWAVCMCS_initBitstream( NSWAVC_bitStream_t_MCS *bS ) { bS->bitPos = 0; bS->byteCnt = 0; bS->currBuff = 0; bS->prevByte = 0xff; bS->prevPrevByte = 0xff; return M4NO_ERROR; } M4OSA_ERR NSWAVCMCS_putBits( NSWAVC_bitStream_t_MCS *bS, M4OSA_UInt32 value, M4OSA_UInt8 length ) { M4OSA_UInt32 maskedValue = 0, temp = 0; M4OSA_UInt8 byteOne; M4OSA_UInt32 len1 = (length == 32) ? 31 : length; if( !(length) ) { /* Length = 0, return OK*/ return M4NO_ERROR; } maskedValue = (M4OSA_UInt32)(value &(( 1 << len1) - 1)); if( 32 > (length + bS->bitPos) ) { bS->bitPos += length; bS->currBuff |= maskedValue << (32 - bS->bitPos); } else { temp = (( bS->bitPos + length) - 32); bS->currBuff |= (maskedValue >> (temp)); byteOne = bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)(bS->currBuff >> 24); if( (( bS->prevPrevByte == 0) & (bS->prevByte == 0) & (!(byteOne & 0xFC))) ) { bS->byteCnt -= 1; bS->prevPrevByte = bS->streamBuffer[bS->byteCnt++] = 0x03; bS->prevByte = bS->streamBuffer[bS->byteCnt++] = byteOne; } else { bS->prevPrevByte = bS->prevByte; bS->prevByte = byteOne; } byteOne = bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)(( bS->currBuff >> 16) & 0xff); if( (( bS->prevPrevByte == 0) & (bS->prevByte == 0) & (!(byteOne & 0xFC))) ) { bS->byteCnt -= 1; bS->prevPrevByte = bS->streamBuffer[bS->byteCnt++] = 0x03; bS->prevByte = bS->streamBuffer[bS->byteCnt++] = byteOne; } else { bS->prevPrevByte = bS->prevByte; bS->prevByte = byteOne; } byteOne = bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)(( bS->currBuff >> 8) & 0xff); if( (( bS->prevPrevByte == 0) & (bS->prevByte == 0) & (!(byteOne & 0xFC))) ) { bS->byteCnt -= 1; bS->prevPrevByte = bS->streamBuffer[bS->byteCnt++] = 0x03; bS->prevByte = bS->streamBuffer[bS->byteCnt++] = byteOne; } else { bS->prevPrevByte = bS->prevByte; bS->prevByte = byteOne; } byteOne = bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)((bS->currBuff) &0xff); if( (( bS->prevPrevByte == 0) & (bS->prevByte == 0) & (!(byteOne & 0xFC))) ) { bS->byteCnt -= 1; bS->prevPrevByte = bS->streamBuffer[bS->byteCnt++] = 0x03; bS->prevByte = bS->streamBuffer[bS->byteCnt++] = byteOne; } else { bS->prevPrevByte = bS->prevByte; bS->prevByte = byteOne; } bS->currBuff = 0; bS->currBuff |= ( maskedValue &(( 1 << temp) - 1)) << (32 - temp); bS->bitPos = temp; } return M4NO_ERROR; } M4OSA_ERR NSWAVCMCS_putBit( NSWAVC_bitStream_t_MCS *bS, M4OSA_UInt32 value ) { M4OSA_UInt32 maskedValue = 0, temp = 0; M4OSA_UInt8 byteOne; maskedValue = (value ? 1 : 0); if( 32 > (1 + bS->bitPos) ) { bS->bitPos += 1; bS->currBuff |= maskedValue << (32 - bS->bitPos); } else { temp = 0; bS->currBuff |= (maskedValue); /* writing it to memory*/ byteOne = bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)(bS->currBuff >> 24); if( (( bS->prevPrevByte == 0) & (bS->prevByte == 0) & (!(byteOne & 0xFC))) ) { bS->byteCnt -= 1; bS->prevPrevByte = bS->streamBuffer[bS->byteCnt++] = 0x03; bS->prevByte = bS->streamBuffer[bS->byteCnt++] = byteOne; } else { bS->prevPrevByte = bS->prevByte; bS->prevByte = byteOne; } byteOne = bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)(( bS->currBuff >> 16) & 0xff); if( (( bS->prevPrevByte == 0) & (bS->prevByte == 0) & (!(byteOne & 0xFC))) ) { bS->byteCnt -= 1; bS->prevPrevByte = bS->streamBuffer[bS->byteCnt++] = 0x03; bS->prevByte = bS->streamBuffer[bS->byteCnt++] = byteOne; } else { bS->prevPrevByte = bS->prevByte; bS->prevByte = byteOne; } byteOne = bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)(( bS->currBuff >> 8) & 0xff); if( (( bS->prevPrevByte == 0) & (bS->prevByte == 0) & (!(byteOne & 0xFC))) ) { bS->byteCnt -= 1; bS->prevPrevByte = bS->streamBuffer[bS->byteCnt++] = 0x03; bS->prevByte = bS->streamBuffer[bS->byteCnt++] = byteOne; } else { bS->prevPrevByte = bS->prevByte; bS->prevByte = byteOne; } byteOne = bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)((bS->currBuff) &0xff); if( (( bS->prevPrevByte == 0) & (bS->prevByte == 0) & (!(byteOne & 0xFC))) ) { bS->byteCnt -= 1; bS->prevPrevByte = bS->streamBuffer[bS->byteCnt++] = 0x03; bS->prevByte = bS->streamBuffer[bS->byteCnt++] = byteOne; } else { bS->prevPrevByte = bS->prevByte; bS->prevByte = byteOne; } bS->currBuff = 0; bS->bitPos = 0; } return M4NO_ERROR; } M4OSA_Int32 NSWAVCMCS_putRbspTbits( NSWAVC_bitStream_t_MCS *bS ) { M4OSA_UInt8 trailBits = 0; M4OSA_UInt8 byteCnt = 0; trailBits = (M4OSA_UInt8)(bS->bitPos % 8); /* Already in the byte aligned position, RBSP trailing bits will be 1000 0000 */ if( 0 == trailBits ) { trailBits = (1 << 7); NSWAVCMCS_putBits(bS, trailBits, 8); } else { trailBits = (8 - trailBits); NSWAVCMCS_putBit(bS, 1); trailBits--; if( trailBits ) { /* put trailBits times zeros */ NSWAVCMCS_putBits(bS, 0, trailBits); } } /* For writting the currBuff in streamBuff 4byte alignment is required*/ byteCnt = (M4OSA_UInt8)(( bS->bitPos + 4) / 8); switch( byteCnt ) { case 1: bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)(bS->currBuff >> 24); break; case 2: bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)(bS->currBuff >> 24); bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)(( bS->currBuff >> 16) & 0xff); break; case 3: bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)(bS->currBuff >> 24); bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)(( bS->currBuff >> 16) & 0xff); bS->streamBuffer[bS->byteCnt++] = (M4OSA_UInt8)(( bS->currBuff >> 8) & 0xff); break; default: /* It will not come here */ break; } // bS->bitPos =0; // bS->currBuff = 0; return M4NO_ERROR; } M4OSA_ERR NSWAVCMCS_uExpVLC( NSWAVC_bitStream_t_MCS *bS, M4OSA_Int32 codeNum ) { M4OSA_Int32 loop, temp; M4OSA_Int32 data = 0; M4OSA_UInt8 codeLen = 0; /* The codeNum cannot be less than zero for this ue(v) */ if( codeNum < 0 ) { return 0; } /* Implementation for Encoding of the Table 9-1 in the Standard */ temp = codeNum + 1; for ( loop = 0; temp != 0; loop++ ) { temp /= 2; } codeLen = (( loop * 2) - 1); data = codeNum + 1; NSWAVCMCS_putBits(bS, data, codeLen); return M4NO_ERROR; } M4OSA_ERR NSWAVCMCS_sExpVLC( NSWAVC_bitStream_t_MCS *bS, M4OSA_Int32 codeNum ) { M4OSA_Int32 loop, temp1, temp2; M4OSA_Int32 data = 0; M4OSA_UInt8 codeLen = 0, isPositive = 0; M4OSA_UInt32 abscodeNum; if( codeNum > 0 ) { isPositive = 1; } if( codeNum > 0 ) { abscodeNum = codeNum; } else { abscodeNum = -codeNum; } temp1 = ( ( ( abscodeNum) << 1) - isPositive) + 1; temp2 = temp1; for ( loop = 0; loop < 16 && temp2 != 0; loop++ ) { temp2 /= 2; } codeLen = ( loop * 2) - 1; data = temp1; NSWAVCMCS_putBits(bS, data, codeLen); return M4NO_ERROR; } M4OSA_ERR H264MCS_ProcessEncodedNALU( M4OSA_Void *ainstance, M4OSA_UInt8 *inbuff, M4OSA_Int32 inbuf_size, M4OSA_UInt8 *outbuff, M4OSA_Int32 *outbuf_size ) { ComBitStreamMCS_t *p_bs, bs; NSWAVC_MCS_t *instance; M4OSA_UInt8 nalu_info; M4OSA_Int32 forbidden_bit, nal_ref_idc, nal_unit_type; M4OSA_Int32 first_mb_in_slice, slice_type, pic_parameter_set_id, frame_num; M4OSA_Int32 seq_parameter_set_id; M4OSA_UInt8 temp1, temp2, temp3, temp4; M4OSA_Int32 temp_frame_num; M4OSA_Int32 bitstoDiacard, bytes; M4OSA_UInt32 mask_bits = 0xFFFFFFFF; M4OSA_Int32 new_bytes, init_bit_pos; M4OSA_UInt32 nal_size; M4OSA_UInt32 cnt; M4OSA_UInt32 outbuffpos = 0; M4OSA_UInt32 nal_size_low16, nal_size_high16; M4OSA_UInt32 frame_size = 0; M4OSA_UInt32 temp = 0; // StageFright encoder does not provide the size in the first 4 bytes of the AU, add it M4OSA_Int8 *pTmpBuff1 = M4OSA_NULL; M4OSA_Int8 *pTmpBuff2 = M4OSA_NULL; p_bs = &bs; instance = (NSWAVC_MCS_t *)ainstance; M4OSA_TRACE1_2( "In H264MCS_ProcessEncodedNALU with FrameSize = %d inBuf_Size=%d", frame_size, inbuf_size); // StageFright codecs may add a start code, make sure it is not present if( !memcmp((void *)inbuff, "\x00\x00\x00\x01", 4) ) { M4OSA_TRACE1_3( "H264MCS_ProcessNALU ERROR : NALU start code has not been removed %d " "0x%X 0x%X", inbuf_size, ((M4OSA_UInt32 *)inbuff)[0], ((M4OSA_UInt32 *)inbuff)[1]); return M4ERR_PARAMETER; } // StageFright encoder does not provide the size in the first 4 bytes of the AU, add it pTmpBuff1 = (M4OSA_Int8 *)M4OSA_32bitAlignedMalloc(inbuf_size + 4, M4MCS, (M4OSA_Char *)"tmpNALU"); memcpy((void *)(pTmpBuff1 + 4), (void *)inbuff, inbuf_size); pTmpBuff1[3] = ( (M4OSA_UInt32)inbuf_size) & 0x000000FF; pTmpBuff1[2] = ( (M4OSA_UInt32)inbuf_size >> 8) & 0x000000FF; pTmpBuff1[1] = ( (M4OSA_UInt32)inbuf_size >> 16) & 0x000000FF; pTmpBuff1[0] = ( (M4OSA_UInt32)inbuf_size >> 24) & 0x000000FF; pTmpBuff2 = (M4OSA_Int8 *)inbuff; inbuff = (M4OSA_UInt8 *)pTmpBuff1; inbuf_size += 4; // Make sure the available size was set if( inbuf_size >= *outbuf_size ) { M4OSA_TRACE1_1( "!!! H264MCS_ProcessNALU ERROR : specified available size is incorrect %d ", *outbuf_size); return M4ERR_PARAMETER; } while( (M4OSA_Int32)frame_size < inbuf_size ) { mask_bits = 0xFFFFFFFF; p_bs->Buffer = (M4OSA_UInt8 *)(inbuff + frame_size); // Use unsigned value to fix errors due to bit sign extension, this fix should be generic nal_size_high16 = ( ( (M4OSA_UInt8 *)p_bs->Buffer)[0] << 8) + ((M4OSA_UInt8 *)p_bs->Buffer)[1]; nal_size_low16 = ( ( (M4OSA_UInt8 *)p_bs->Buffer)[2] << 8) + ((M4OSA_UInt8 *)p_bs->Buffer)[3]; nalu_info = (unsigned char)p_bs->Buffer[4]; outbuff[outbuffpos] = p_bs->Buffer[4]; p_bs->Buffer = p_bs->Buffer + 5; p_bs->bitPos = 0; p_bs->lastTotalBits = 0; p_bs->numBitsInBuffer = ( inbuf_size - frame_size - 5) << 3; p_bs->readableBytesInBuffer = inbuf_size - frame_size - 5; p_bs->ui32TempBuff = 0; p_bs->i8BitCnt = 0; p_bs->pui8BfrPtr = (M4OSA_Int8 *)p_bs->Buffer; p_bs->ui32LastTwoBytes = 0xFFFFFFFF; H264MCS_getBits(p_bs, 0); nal_size = ( nal_size_high16 << 16) + nal_size_low16; frame_size += nal_size + 4; forbidden_bit = ( nalu_info >> 7) & 1; nal_ref_idc = ( nalu_info >> 5) & 3; nal_unit_type = (nalu_info) &0x1f; NSWAVCMCS_initBitstream(&instance->encbs); instance->encbs.streamBuffer = outbuff + outbuffpos + 1; if( nal_unit_type == 8 ) { M4OSA_TRACE1_0("Error : PPS"); return 0; } if( nal_unit_type == 7 ) { /*SPS Packet */ M4OSA_TRACE1_0("Error : SPS"); return 0; } if( (nal_unit_type == 5) ) { instance->frame_count = 0; instance->POC_lsb = 0; } if( ( nal_unit_type == 1) || (nal_unit_type == 5) ) { first_mb_in_slice = H264MCS_DecVLCReadExpGolombCode(p_bs); slice_type = H264MCS_DecVLCReadExpGolombCode(p_bs); pic_parameter_set_id = H264MCS_DecVLCReadExpGolombCode(p_bs); /* First MB in slice */ NSWAVCMCS_uExpVLC(&instance->encbs, first_mb_in_slice); /* Slice Type */ NSWAVCMCS_uExpVLC(&instance->encbs, slice_type); /* Picture Parameter set Id */ pic_parameter_set_id = instance->encoder_pps.pic_parameter_set_id; NSWAVCMCS_uExpVLC(&instance->encbs, pic_parameter_set_id); temp = H264MCS_getBits(p_bs, instance->encoder_sps.log2_max_frame_num_minus4 + 4); NSWAVCMCS_putBits(&instance->encbs, instance->frame_count, instance->clip_sps.log2_max_frame_num_minus4 + 4); // In Baseline Profile: frame_mbs_only_flag should be ON if( nal_unit_type == 5 ) { temp = H264MCS_DecVLCReadExpGolombCode(p_bs); NSWAVCMCS_uExpVLC(&instance->encbs, temp); } if( instance->encoder_sps.pic_order_cnt_type == 0 ) { temp = H264MCS_getBits(p_bs, instance->encoder_sps.log2_max_pic_order_cnt_lsb_minus4 + 4); // in baseline profile field_pic_flag should be off. if( instance->encoder_pps.pic_order_present_flag ) { temp = H264MCS_DecVLCReadSignedExpGolombCode(p_bs); } } if( ( instance->encoder_sps.pic_order_cnt_type == 1) && (instance->encoder_sps.delta_pic_order_always_zero_flag) ) { temp = H264MCS_DecVLCReadSignedExpGolombCode(p_bs); // in baseline profile field_pic_flag should be off. if( instance->encoder_pps.pic_order_present_flag ) { temp = H264MCS_DecVLCReadSignedExpGolombCode(p_bs); } } if( instance->clip_sps.pic_order_cnt_type == 0 ) { NSWAVCMCS_putBits(&instance->encbs, instance->POC_lsb, instance->clip_sps.log2_max_pic_order_cnt_lsb_minus4 + 4); // in baseline profile field_pic_flag should be off. if( instance->encoder_pps.pic_order_present_flag ) { NSWAVCMCS_sExpVLC(&instance->encbs, 0); } } if( ( instance->clip_sps.pic_order_cnt_type == 1) && (instance->clip_sps.delta_pic_order_always_zero_flag) ) { NSWAVCMCS_sExpVLC(&instance->encbs, 0); // in baseline profile field_pic_flag should be off. if( instance->encoder_pps.pic_order_present_flag ) { NSWAVCMCS_sExpVLC(&instance->encbs, 0); } } cnt = p_bs->bitPos & 0x7; if( cnt ) { cnt = 8 - cnt; temp = H264MCS_getBits(p_bs, cnt); NSWAVCMCS_putBits(&instance->encbs, temp, cnt); } cnt = p_bs->bitPos >> 3; while( cnt < (nal_size - 2) ) { temp = H264MCS_getBits(p_bs, 8); NSWAVCMCS_putBits(&instance->encbs, temp, 8); cnt = p_bs->bitPos >> 3; } temp = H264MCS_getBits(p_bs, 8); if( temp != 0 ) { cnt = 0; while( ( temp & 0x1) == 0 ) { cnt++; temp = temp >> 1; } cnt++; temp = temp >> 1; if( 8 - cnt ) { NSWAVCMCS_putBits(&instance->encbs, temp, (8 - cnt)); } NSWAVCMCS_putRbspTbits(&instance->encbs); } else { M4OSA_TRACE1_1( "H264MCS_ProcessEncodedNALU : 13 temp = 0 trailing bits = %d", instance->encbs.bitPos % 8); if( instance->encbs.bitPos % 8 ) { NSWAVCMCS_putBits(&instance->encbs, 0, (8 - instance->encbs.bitPos % 8)); } } temp = instance->encbs.byteCnt; temp = temp + 1; outbuffpos = outbuffpos + temp; } } *outbuf_size = outbuffpos; instance->POC_lsb = instance->POC_lsb + 1; if( instance->POC_lsb == instance->POC_lsb_mod ) { instance->POC_lsb = 0; } instance->frame_count = instance->frame_count + 1; if( instance->frame_count == instance->frame_mod_count ) { instance->frame_count = 0; } // StageFright encoder does not provide the size in the first 4 bytes of the AU, add it free(pTmpBuff1); pTmpBuff1 = M4OSA_NULL; inbuff = (M4OSA_UInt8 *)pTmpBuff2; return M4NO_ERROR; } M4OSA_Int32 DecSPSMCS( ComBitStreamMCS_t *p_bs, ComSequenceParameterSet_t_MCS *sps ) { M4OSA_UInt32 i; M4OSA_Int32 temp_max_dpb_size; M4OSA_Int32 nb_ignore_bits; M4OSA_Int32 error; M4OSA_UInt8 profile_idc, level_idc, reserved_zero_4bits, seq_parameter_set_id; M4OSA_UInt8 constraint_set0_flag, constraint_set1_flag, constraint_set2_flag, constraint_set3_flag; sps->profile_idc = (M4OSA_UInt8)H264MCS_getBits(p_bs, 8); sps->constraint_set0_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); sps->constraint_set1_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); sps->constraint_set2_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); sps->constraint_set3_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); reserved_zero_4bits = (M4OSA_UInt8)H264MCS_getBits(p_bs, 4); sps->level_idc = (M4OSA_UInt8)H264MCS_getBits(p_bs, 8); sps->seq_parameter_set_id = (M4OSA_UInt8)H264MCS_DecVLCReadExpGolombCode(p_bs); sps->log2_max_frame_num_minus4 = (M4OSA_UInt8)H264MCS_DecVLCReadExpGolombCode(p_bs); sps->MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4); sps->pic_order_cnt_type = (M4OSA_UInt8)H264MCS_DecVLCReadExpGolombCode(p_bs); if (sps->pic_order_cnt_type == 0) { sps->log2_max_pic_order_cnt_lsb_minus4 = (M4OSA_UInt8)H264MCS_DecVLCReadExpGolombCode(p_bs); sps->MaxPicOrderCntLsb = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4); } else if( sps->pic_order_cnt_type == 1 ) { sps->delta_pic_order_always_zero_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); // This fix should be generic to remove codec dependency sps->offset_for_non_ref_pic = H264MCS_DecVLCReadSignedExpGolombCode(p_bs); sps->offset_for_top_to_bottom_field = H264MCS_DecVLCReadSignedExpGolombCode(p_bs); /*num_ref_frames_in_pic_order_cnt_cycle must be in the range 0, 255*/ sps->num_ref_frames_in_pic_order_cnt_cycle = (M4OSA_UInt8)H264MCS_DecVLCReadExpGolombCode(p_bs); /* compute deltaPOC */ sps->expectedDeltaPerPicOrderCntCycle = 0; for ( i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++ ) { // This fix should be generic to remove codec dependency sps->offset_for_ref_frame[i] = H264MCS_DecVLCReadSignedExpGolombCode(p_bs); sps->expectedDeltaPerPicOrderCntCycle += sps->offset_for_ref_frame[i]; } } /* num_ref_frames must be in the range 0,16 */ sps->num_ref_frames = (M4OSA_UInt8)H264MCS_DecVLCReadExpGolombCode(p_bs); sps->gaps_in_frame_num_value_allowed_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); sps->pic_width_in_mbs_minus1 = (M4OSA_UInt16)H264MCS_DecVLCReadExpGolombCode(p_bs); sps->pic_height_in_map_units_minus1 = (M4OSA_UInt16)H264MCS_DecVLCReadExpGolombCode(p_bs); sps->frame_mbs_only_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); if (!sps->frame_mbs_only_flag) { sps->mb_adaptive_frame_field_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); } else { sps->mb_adaptive_frame_field_flag = 0; } sps->PicWidthInMbs = sps->pic_width_in_mbs_minus1 + 1; sps->FrameHeightInMbs = ( 2 - sps->frame_mbs_only_flag) * \ (sps->pic_height_in_map_units_minus1 + 1); #ifdef _CAP_FMO_ sps->NumSliceGroupMapUnits = sps->PicWidthInMbs * (sps->pic_height_in_map_units_minus1 + 1); sps->MaxPicSizeInMbs = sps->PicWidthInMbs * sps->FrameHeightInMbs; #endif /*_CAP_FMO_*/ sps->direct_8x8_inference_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); if( sps->frame_mbs_only_flag == 0 ) sps->direct_8x8_inference_flag = 1; sps->frame_cropping_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); if( sps->frame_cropping_flag ) { sps->frame_crop_left_offset = H264MCS_DecVLCReadExpGolombCode(p_bs); sps->frame_crop_right_offset = H264MCS_DecVLCReadExpGolombCode(p_bs); sps->frame_crop_top_offset = H264MCS_DecVLCReadExpGolombCode(p_bs); sps->frame_crop_bottom_offset = H264MCS_DecVLCReadExpGolombCode(p_bs); } else { sps->frame_crop_left_offset = 0; sps->frame_crop_right_offset = 0; sps->frame_crop_top_offset = 0; sps->frame_crop_bottom_offset = 0; } sps->vui_parameters_present_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); if (sps->vui_parameters_present_flag) { /* no error message as stream can be decoded without VUI messages */ } return M4NO_ERROR; } M4OSA_Int32 DecPPSMCS( ComBitStreamMCS_t *p_bs, ComPictureParameterSet_t_MCS *pps ) { M4OSA_Int32 error; M4OSA_UInt32 pic_parameter_set_id; #ifdef _CAP_FMO_ M4OSA_UInt32 i, length, v; #endif M4OSA_Int32 nb_ignore_bits; pic_parameter_set_id = H264MCS_DecVLCReadExpGolombCode(p_bs); pps->pic_parameter_set_id = (M4OSA_UInt8)pic_parameter_set_id; pps->seq_parameter_set_id = (M4OSA_UInt8)H264MCS_DecVLCReadExpGolombCode(p_bs); /* entropy_coding_mode_flag must be 0 or 1 */ pps->entropy_coding_mode_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); pps->pic_order_present_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); pps->num_slice_groups_minus1 = (M4OSA_UInt8)H264MCS_DecVLCReadExpGolombCode(p_bs); #ifdef _CAP_FMO_ /* FMO stuff begins here */ pps->map_initialized = FALSE; if( pps->num_slice_groups_minus1 > 0 ) { pps->slice_group_map_type = (M4OSA_UInt8)H264MCS_DecVLCReadExpGolombCode(p_bs); switch( pps->slice_group_map_type ) { case 0: for ( i = 0; i <= pps->num_slice_groups_minus1; i++ ) { pps->run_length_minus1[i] = (M4OSA_UInt16)H264MCS_DecVLCReadExpGolombCode(p_bs); } break; case 2: for ( i = 0; i < pps->num_slice_groups_minus1; i++ ) { pps->top_left[i] = (M4OSA_UInt16)H264MCS_DecVLCReadExpGolombCode(p_bs); pps->bottom_right[i] = (M4OSA_UInt16)H264MCS_DecVLCReadExpGolombCode(p_bs); } break; case 3: case 4: case 5: pps->slice_group_change_direction_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); pps->slice_group_change_rate_minus1 = (M4OSA_UInt16)H264MCS_DecVLCReadExpGolombCode(p_bs); break; case 6: pps->pic_size_in_map_units_minus1 = (M4OSA_UInt16)H264MCS_DecVLCReadExpGolombCode(p_bs); pps->slice_group_id = (H264UInt8 *)M4H264Dec_malloc((pps->pic_size_in_map_units_minus1 + 1), M4H264_COREID, (M4OSA_Char *)"PPS"); if (M4OSA_NULL == pps->slice_group_id) { M4OSA_TRACE1_0("DecPPSMCS: allocation error"); return M4ERR_ALLOC; } for ( length = 0, v = pps->num_slice_groups_minus1 + 1; v != 0; v >>= 1, length++ ); for ( i = 0; i <= pps->pic_size_in_map_units_minus1; i++ ) { pps->slice_group_id[i] = (M4OSA_UInt8)getBits(p_vlc_engine->p_bs, length); } break; } } else { pps->slice_group_map_type = 0; } /* End of FMO stuff */ #else #endif /* _CAP_FMO_ */ /* num_ref_idx_l0_active_minus1 must be in the range 0, 31 */ pps->num_ref_idx_l0_active_minus1 = (M4OSA_UInt8)H264MCS_DecVLCReadExpGolombCode(p_bs); /* num_ref_idx_l1_active_minus1 must be in the range 0, 31 */ pps->num_ref_idx_l1_active_minus1 = (M4OSA_UInt8)H264MCS_DecVLCReadExpGolombCode(p_bs); pps->weighted_pred_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); /* weighted_bipred_idc must be in the range 0,2 */ pps->weighted_bipred_idc = (M4OSA_Bool)H264MCS_getBits(p_bs, 2); /* pic_init_qp_minus26 must be in the range -26,25 */ pps->pic_init_qp_minus26 = (M4OSA_Int16)H264MCS_DecVLCReadSignedExpGolombCode(p_bs); /* pic_init_qs_minus26 must be in the range -26,25 */ pps->pic_init_qs_minus26 = (M4OSA_Int16)H264MCS_DecVLCReadSignedExpGolombCode(p_bs); /* chroma_qp_index_offset must be in the range -12,+12 */ pps->chroma_qp_index_offset = (M4OSA_Int16)H264MCS_DecVLCReadSignedExpGolombCode(p_bs); pps->deblocking_filter_control_present_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); pps->constrained_intra_pred_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); pps->redundant_pic_cnt_present_flag = (M4OSA_Bool)H264MCS_getBits(p_bs, 1); return M4NO_ERROR; } M4OSA_ERR H264MCS_ProcessSPS_PPS( NSWAVC_MCS_t *instance, M4OSA_UInt8 *inbuff, M4OSA_Int32 inbuf_size ) { ComBitStreamMCS_t *p_bs, bs; ComBitStreamMCS_t *p_bs1, bs1; M4OSA_UInt8 nalu_info = 0; M4OSA_Int32 forbidden_bit, nal_ref_idc, nal_unit_type; M4OSA_Int32 first_mb_in_slice, slice_type, pic_parameter_set_id = 0, frame_num; M4OSA_Int32 seq_parameter_set_id; M4OSA_UInt8 temp1, temp2, temp3, temp4; M4OSA_Int32 temp_frame_num; M4OSA_Int32 bitstoDiacard, bytes; M4OSA_UInt32 mask_bits = 0xFFFFFFFF; M4OSA_Int32 new_bytes, init_bit_pos; M4OSA_UInt32 nal_size = 0; M4OSA_UInt32 cnt, cnt1; M4OSA_UInt32 outbuffpos = 0; M4OSA_UInt32 nal_size_low16, nal_size_high16; M4OSA_UInt32 frame_size = 0; M4OSA_UInt32 temp = 0; M4OSA_UInt8 *lClipDSI; M4OSA_UInt8 *lClipDSI_PPS_start; M4OSA_UInt32 lClipDSI_PPS_offset = 0; M4OSA_UInt8 *lPPS_Buffer = M4OSA_NULL; M4OSA_UInt32 lPPS_Buffer_Size = 0; M4OSA_UInt32 lSize, lSize1; M4OSA_UInt32 lActiveSPSID_Clip; M4OSA_UInt32 lClipPPSRemBits = 0; M4OSA_UInt32 lEncoder_SPSID = 0; M4OSA_UInt32 lEncoder_PPSID = 0; M4OSA_UInt32 lEncoderPPSRemBits = 0; M4OSA_UInt32 lFound = 0; M4OSA_UInt32 size; M4OSA_UInt8 Clip_SPSID[32] = { 0 }; M4OSA_UInt8 Clip_UsedSPSID[32] = { 0 }; M4OSA_UInt8 Clip_PPSID[256] = { 0 }; M4OSA_UInt8 Clip_SPSID_in_PPS[256] = { 0 }; M4OSA_UInt8 Clip_UsedPPSID[256] = { 0 }; M4OSA_ERR err = M4NO_ERROR; p_bs = &bs; p_bs1 = &bs1; /* Find the active SPS ID */ M4OSA_DEBUG_IF2((M4OSA_NULL == instance), M4ERR_PARAMETER, "H264MCS_ProcessSPS_PPS: instance is M4OSA_NULL"); switch( instance->m_pDecoderSpecificInfo[4] & 0x3 ) { case 0: instance->m_Num_Bytes_NALUnitLength = 1; break; case 1: instance->m_Num_Bytes_NALUnitLength = 2; break; case 3: //Note: Current code supports only this... instance->m_Num_Bytes_NALUnitLength = 4; break; } instance->m_encoder_SPS_Cnt = instance->m_pDecoderSpecificInfo[5] & 0x1F; lClipDSI = instance->m_pDecoderSpecificInfo + 6; lClipDSI_PPS_offset = 6; for ( cnt = 0; cnt < instance->m_encoder_SPS_Cnt; cnt++ ) { lSize = ( lClipDSI[0] << 8) + lClipDSI[1]; lClipDSI = lClipDSI + 2; p_bs->Buffer = (M4OSA_UInt8 *)(lClipDSI + 4); DecBitStreamReset_MCS(p_bs, lSize - 4); Clip_SPSID[cnt] = H264MCS_DecVLCReadExpGolombCode(p_bs); Clip_UsedSPSID[Clip_SPSID[cnt]] = 1; lClipDSI = lClipDSI + lSize; lClipDSI_PPS_offset = lClipDSI_PPS_offset + 2 + lSize; } instance->m_encoder_PPS_Cnt = lClipDSI[0]; lClipDSI = lClipDSI + 1; lClipDSI_PPS_start = lClipDSI; for ( cnt = 0; cnt < instance->m_encoder_PPS_Cnt; cnt++ ) { lSize = ( lClipDSI[0] << 8) + lClipDSI[1]; lClipDSI = lClipDSI + 2; p_bs->Buffer = (M4OSA_UInt8 *)(lClipDSI + 1); DecBitStreamReset_MCS(p_bs, lSize - 1); Clip_PPSID[cnt] = H264MCS_DecVLCReadExpGolombCode(p_bs); Clip_UsedPPSID[Clip_PPSID[cnt]] = 1; Clip_SPSID_in_PPS[Clip_PPSID[cnt]] = H264MCS_DecVLCReadExpGolombCode(p_bs); lClipDSI = lClipDSI + lSize; } /* Find the clip SPS ID used at the cut start frame */ while( ( (M4OSA_Int32)frame_size) < inbuf_size ) { mask_bits = 0xFFFFFFFF; p_bs->Buffer = (M4OSA_UInt8 *)(inbuff + frame_size); switch( instance->m_Num_Bytes_NALUnitLength ) { case 1: nal_size = (unsigned char)p_bs->Buffer[0]; nalu_info = (unsigned char)p_bs->Buffer[1]; p_bs->Buffer = p_bs->Buffer + 2; break; case 2: nal_size_high16 = ( p_bs->Buffer[0] << 8) + p_bs->Buffer[1]; nal_size = nal_size_high16; nalu_info = (unsigned char)p_bs->Buffer[2]; p_bs->Buffer = p_bs->Buffer + 3; break; case 4: nal_size_high16 = ( p_bs->Buffer[0] << 8) + p_bs->Buffer[1]; nal_size_low16 = ( p_bs->Buffer[2] << 8) + p_bs->Buffer[3]; nal_size = ( nal_size_high16 << 16) + nal_size_low16; nalu_info = (unsigned char)p_bs->Buffer[4]; p_bs->Buffer = p_bs->Buffer + 5; break; } p_bs->bitPos = 0; p_bs->lastTotalBits = 0; p_bs->numBitsInBuffer = ( inbuf_size - frame_size - instance->m_Num_Bytes_NALUnitLength - 1) << 3; p_bs->readableBytesInBuffer = inbuf_size - frame_size - instance->m_Num_Bytes_NALUnitLength - 1; p_bs->ui32TempBuff = 0; p_bs->i8BitCnt = 0; p_bs->pui8BfrPtr = (M4OSA_Int8 *)p_bs->Buffer; p_bs->ui32LastTwoBytes = 0xFFFFFFFF; H264MCS_getBits(p_bs, 0); frame_size += nal_size + instance->m_Num_Bytes_NALUnitLength; forbidden_bit = ( nalu_info >> 7) & 1; nal_ref_idc = ( nalu_info >> 5) & 3; nal_unit_type = (nalu_info) &0x1f; if( nal_unit_type == 8 ) { M4OSA_TRACE1_0("H264MCS_ProcessSPS_PPS() Error: PPS"); return err; } if( nal_unit_type == 7 ) { /*SPS Packet */ M4OSA_TRACE1_0("H264MCS_ProcessSPS_PPS() Error: SPS"); return err; } if( ( nal_unit_type == 1) || (nal_unit_type == 5) ) { first_mb_in_slice = H264MCS_DecVLCReadExpGolombCode(p_bs); slice_type = H264MCS_DecVLCReadExpGolombCode(p_bs); pic_parameter_set_id = H264MCS_DecVLCReadExpGolombCode(p_bs); break; } } lActiveSPSID_Clip = Clip_SPSID_in_PPS[pic_parameter_set_id]; instance->final_SPS_ID = lActiveSPSID_Clip; /* Do we need to add encoder PPS to clip PPS */ lClipDSI = lClipDSI_PPS_start; for ( cnt = 0; cnt < instance->m_encoder_PPS_Cnt; cnt++ ) { lSize = ( lClipDSI[0] << 8) + lClipDSI[1]; lClipDSI = lClipDSI + 2; if( lActiveSPSID_Clip == Clip_SPSID_in_PPS[Clip_PPSID[cnt]] ) { lPPS_Buffer = lClipDSI + 1; lPPS_Buffer_Size = lSize - 1; p_bs->Buffer = (M4OSA_UInt8 *)(lClipDSI + 1); DecBitStreamReset_MCS(p_bs, lSize - 1); Clip_PPSID[cnt] = H264MCS_DecVLCReadExpGolombCode(p_bs); Clip_UsedPPSID[Clip_SPSID[cnt]] = 1; Clip_SPSID_in_PPS[cnt] = H264MCS_DecVLCReadExpGolombCode(p_bs); lClipPPSRemBits = ( lSize - 1) << 3; lClipPPSRemBits -= p_bs->bitPos; temp = lClipDSI[lSize - 1]; cnt1 = 0; while( ( temp & 0x1) == 0 ) { cnt1++; temp = temp >> 1; } cnt1++; lClipPPSRemBits -= cnt1; lSize1 = instance->m_encoderPPSSize - 1; p_bs1->Buffer = (M4OSA_UInt8 *)(instance->m_pEncoderPPS + 1); DecBitStreamReset_MCS(p_bs1, lSize1); lEncoder_PPSID = H264MCS_DecVLCReadExpGolombCode(p_bs1); lEncoder_SPSID = H264MCS_DecVLCReadExpGolombCode(p_bs1); lEncoderPPSRemBits = ( lSize1) << 3; lEncoderPPSRemBits -= p_bs1->bitPos; temp = instance->m_pEncoderPPS[lSize1]; cnt1 = 0; while( ( temp & 0x1) == 0 ) { cnt1++; temp = temp >> 1; } cnt1++; lEncoderPPSRemBits -= cnt1; if( lEncoderPPSRemBits == lClipPPSRemBits ) { while( lEncoderPPSRemBits > 8 ) { temp1 = H264MCS_getBits(p_bs, 8); temp2 = H264MCS_getBits(p_bs1, 8); lEncoderPPSRemBits = lEncoderPPSRemBits - 8; if( temp1 != temp2 ) { break; } } if( lEncoderPPSRemBits < 8 ) { if( lEncoderPPSRemBits ) { temp1 = H264MCS_getBits(p_bs, lEncoderPPSRemBits); temp2 = H264MCS_getBits(p_bs1, lEncoderPPSRemBits); if( temp1 == temp2 ) { lFound = 1; } } else { lFound = 1; } } break; } } lClipDSI = lClipDSI + lSize; } /* Form the final SPS and PPS data */ if( lFound == 1 ) { /* No need to add PPS */ instance->final_PPS_ID = Clip_PPSID[cnt]; instance->m_pFinalDSI = (M4OSA_UInt8 *)M4OSA_32bitAlignedMalloc(instance->m_decoderSpecificInfoSize, M4MCS, (M4OSA_Char *)"instance->m_pFinalDSI"); if( instance->m_pFinalDSI == M4OSA_NULL ) { M4OSA_TRACE1_0("instance->m_pFinalDSI: allocation error"); return M4ERR_ALLOC; } instance->m_pFinalDSISize = instance->m_decoderSpecificInfoSize; memcpy((void *)instance->m_pFinalDSI, (void *)instance->m_pDecoderSpecificInfo, instance->m_decoderSpecificInfoSize); } else { /* ADD PPS */ /* find the free PPS ID */ cnt = 0; while( Clip_UsedPPSID[cnt] ) { cnt++; } instance->final_PPS_ID = cnt; size = instance->m_decoderSpecificInfoSize + instance->m_encoderPPSSize + 10; instance->m_pFinalDSI = (M4OSA_UInt8 *)M4OSA_32bitAlignedMalloc(size, M4MCS, (M4OSA_Char *)"instance->m_pFinalDSI"); if( instance->m_pFinalDSI == M4OSA_NULL ) { M4OSA_TRACE1_0("instance->m_pFinalDSI: allocation error"); return M4ERR_ALLOC; } memcpy((void *)instance->m_pFinalDSI, (void *)instance->m_pDecoderSpecificInfo, instance->m_decoderSpecificInfoSize); temp = instance->m_pFinalDSI[lClipDSI_PPS_offset]; temp = temp + 1; instance->m_pFinalDSI[lClipDSI_PPS_offset] = temp; //temp = instance->m_pEncoderPPS[0]; lSize1 = instance->m_encoderPPSSize - 1; p_bs1->Buffer = (M4OSA_UInt8 *)(instance->m_pEncoderPPS + 1); DecBitStreamReset_MCS(p_bs1, lSize1); lEncoder_PPSID = H264MCS_DecVLCReadExpGolombCode(p_bs1); lEncoder_SPSID = H264MCS_DecVLCReadExpGolombCode(p_bs1); lEncoderPPSRemBits = ( lSize1) << 3; lEncoderPPSRemBits -= p_bs1->bitPos; temp = instance->m_pEncoderPPS[lSize1]; cnt1 = 0; while( ( temp & 0x1) == 0 ) { cnt1++; temp = temp >> 1; } cnt1++; lEncoderPPSRemBits -= cnt1; instance->m_pFinalDSI[instance->m_decoderSpecificInfoSize + 2] = instance->m_pEncoderPPS[0]; NSWAVCMCS_initBitstream(&instance->encbs); instance->encbs.streamBuffer = &(instance->m_pFinalDSI[instance->m_decoderSpecificInfoSize + 3]); lPPS_Buffer = instance->encbs.streamBuffer; NSWAVCMCS_uExpVLC(&instance->encbs, instance->final_PPS_ID); NSWAVCMCS_uExpVLC(&instance->encbs, instance->final_SPS_ID); while( lEncoderPPSRemBits > 8 ) { temp = H264MCS_getBits(p_bs1, 8); NSWAVCMCS_putBits(&instance->encbs, temp, 8); lEncoderPPSRemBits = lEncoderPPSRemBits - 8; } if( lEncoderPPSRemBits ) { temp = H264MCS_getBits(p_bs1, lEncoderPPSRemBits); NSWAVCMCS_putBits(&instance->encbs, temp, lEncoderPPSRemBits); } NSWAVCMCS_putRbspTbits(&instance->encbs); temp = instance->encbs.byteCnt; lPPS_Buffer_Size = temp; temp = temp + 1; instance->m_pFinalDSI[instance->m_decoderSpecificInfoSize] = ( temp >> 8) & 0xFF; instance->m_pFinalDSI[instance->m_decoderSpecificInfoSize + 1] = (temp) &0xFF; instance->m_pFinalDSISize = instance->m_decoderSpecificInfoSize + 2 + temp; } /* Decode the clip SPS */ lClipDSI = instance->m_pDecoderSpecificInfo + 6; lClipDSI_PPS_offset = 6; for ( cnt = 0; cnt < instance->m_encoder_SPS_Cnt; cnt++ ) { lSize = ( lClipDSI[0] << 8) + lClipDSI[1]; lClipDSI = lClipDSI + 2; if( Clip_SPSID[cnt] == instance->final_SPS_ID ) { p_bs->Buffer = (M4OSA_UInt8 *)(lClipDSI + 1); DecBitStreamReset_MCS(p_bs, lSize - 1); err = DecSPSMCS(p_bs, &instance->clip_sps); if(err != M4NO_ERROR) { return M4ERR_PARAMETER; } //Clip_SPSID[cnt] = H264MCS_DecVLCReadExpGolombCode(p_bs); //Clip_UsedSPSID[Clip_SPSID[cnt]] = 1; break; } lClipDSI = lClipDSI + lSize; } /* Decode encoder SPS */ p_bs->Buffer = (M4OSA_UInt8 *)(instance->m_pEncoderSPS + 1); DecBitStreamReset_MCS(p_bs, instance->m_encoderSPSSize - 1); err = DecSPSMCS(p_bs, &instance->encoder_sps); if(err != M4NO_ERROR) { return M4ERR_PARAMETER; } if( instance->encoder_sps.num_ref_frames > instance->clip_sps.num_ref_frames ) { return 100; //not supported } p_bs->Buffer = (M4OSA_UInt8 *)lPPS_Buffer; DecBitStreamReset_MCS(p_bs, lPPS_Buffer_Size); DecPPSMCS(p_bs, &instance->encoder_pps); instance->frame_count = 0; instance->frame_mod_count = 1 << (instance->clip_sps.log2_max_frame_num_minus4 + 4); instance->POC_lsb = 0; instance->POC_lsb_mod = 1 << (instance->clip_sps.log2_max_pic_order_cnt_lsb_minus4 + 4); return M4NO_ERROR; } M4OSA_ERR H264MCS_ProcessNALU( NSWAVC_MCS_t *ainstance, M4OSA_UInt8 *inbuff, M4OSA_Int32 inbuf_size, M4OSA_UInt8 *outbuff, M4OSA_Int32 *outbuf_size ) { ComBitStreamMCS_t *p_bs, bs; NSWAVC_MCS_t *instance; M4OSA_UInt8 nalu_info; M4OSA_Int32 forbidden_bit, nal_ref_idc, nal_unit_type; M4OSA_Int32 first_mb_in_slice, slice_type, pic_parameter_set_id, frame_num; M4OSA_Int32 seq_parameter_set_id; M4OSA_UInt8 temp1, temp2, temp3, temp4; M4OSA_Int32 temp_frame_num; M4OSA_Int32 bitstoDiacard, bytes; M4OSA_UInt32 mask_bits = 0xFFFFFFFF; M4OSA_Int32 new_bytes, init_bit_pos; M4OSA_UInt32 nal_size; M4OSA_UInt32 cnt; M4OSA_UInt32 outbuffpos = 0; //#ifndef DGR_FIX // + new M4OSA_UInt32 nal_size_low16, nal_size_high16; //#endif // + end new M4OSA_UInt32 frame_size = 0; M4OSA_UInt32 temp = 0; M4OSA_ERR err = M4NO_ERROR; M4OSA_UInt8 *buff; p_bs = &bs; instance = (NSWAVC_MCS_t *)ainstance; M4OSA_DEBUG_IF2((M4OSA_NULL == instance), M4ERR_PARAMETER, "H264MCS_ProcessNALU: instance is M4OSA_NULL"); if( instance->is_done ) return err; inbuff[0] = 0x00; inbuff[1] = 0x00; inbuff[2] = 0x00; inbuff[3] = 0x01; while( (M4OSA_Int32)frame_size < inbuf_size ) { mask_bits = 0xFFFFFFFF; p_bs->Buffer = (M4OSA_UInt8 *)(inbuff + frame_size); nalu_info = (unsigned char)p_bs->Buffer[4]; outbuff[outbuffpos] = p_bs->Buffer[0]; outbuff[outbuffpos + 1] = p_bs->Buffer[1]; outbuff[outbuffpos + 2] = p_bs->Buffer[2]; outbuff[outbuffpos + 3] = p_bs->Buffer[3]; outbuff[outbuffpos + 4] = p_bs->Buffer[4]; p_bs->Buffer = p_bs->Buffer + 5; p_bs->bitPos = 0; p_bs->lastTotalBits = 0; p_bs->numBitsInBuffer = ( inbuf_size - frame_size - 5) << 3; p_bs->readableBytesInBuffer = inbuf_size - frame_size - 5; p_bs->ui32TempBuff = 0; p_bs->i8BitCnt = 0; p_bs->pui8BfrPtr = (M4OSA_Int8 *)p_bs->Buffer; p_bs->ui32LastTwoBytes = 0xFFFFFFFF; H264MCS_getBits(p_bs, 0); nal_size = inbuf_size - frame_size - 4; buff = inbuff + frame_size + 4; while( nal_size > 4 ) { if( ( buff[0] == 0x00) && (buff[1] == 0x00) && (buff[2] == 0x00) && (buff[3] == 0x01) ) { break; } buff = buff + 1; nal_size = nal_size - 1; } if( nal_size <= 4 ) { nal_size = 0; } nal_size = ( inbuf_size - frame_size - 4) - nal_size; // M4OSA_TRACE1_3("H264MCS_ProcessNALU frame input buff size = %d current position //= %d nal size = %d", // inbuf_size, frame_size, nal_size + 4); frame_size += nal_size + 4; forbidden_bit = ( nalu_info >> 7) & 1; nal_ref_idc = ( nalu_info >> 5) & 3; nal_unit_type = (nalu_info) &0x1f; if( nal_unit_type == 5 ) { /*IDR/PPS Packet - Do nothing*/ instance->is_done = 1; return err; } NSWAVCMCS_initBitstream(&instance->encbs); instance->encbs.streamBuffer = outbuff + outbuffpos + 5; if( nal_unit_type == 8 ) { M4OSA_TRACE1_0("H264MCS_ProcessNALU() Error: PPS"); return err; } if( nal_unit_type == 7 ) { /*SPS Packet */ M4OSA_TRACE1_0("H264MCS_ProcessNALU() Error: SPS"); return 0; } if( (nal_unit_type == 5) ) { instance->frame_count = 0; instance->POC_lsb = 0; } if( (nal_unit_type == 1) ) { first_mb_in_slice = H264MCS_DecVLCReadExpGolombCode(p_bs); NSWAVCMCS_uExpVLC(&instance->encbs, first_mb_in_slice); slice_type = H264MCS_DecVLCReadExpGolombCode(p_bs); NSWAVCMCS_uExpVLC(&instance->encbs, slice_type); pic_parameter_set_id = H264MCS_DecVLCReadExpGolombCode(p_bs); NSWAVCMCS_uExpVLC(&instance->encbs, pic_parameter_set_id); temp = H264MCS_getBits(p_bs, instance->clip_sps.log2_max_frame_num_minus4 + 4); NSWAVCMCS_putBits(&instance->encbs, instance->frame_count, instance->clip_sps.log2_max_frame_num_minus4 + 4); // In Baseline Profile: frame_mbs_only_flag should be ON if( nal_unit_type == 5 ) { temp = H264MCS_DecVLCReadExpGolombCode(p_bs); NSWAVCMCS_uExpVLC(&instance->encbs, temp); } if( instance->clip_sps.pic_order_cnt_type == 0 ) { temp = H264MCS_getBits(p_bs, instance->clip_sps.log2_max_pic_order_cnt_lsb_minus4 + 4); NSWAVCMCS_putBits(&instance->encbs, instance->POC_lsb, instance->clip_sps.log2_max_pic_order_cnt_lsb_minus4 + 4); } if( ( instance->clip_sps.pic_order_cnt_type == 1) && (instance->clip_sps.delta_pic_order_always_zero_flag) ) { temp = H264MCS_DecVLCReadSignedExpGolombCode(p_bs); NSWAVCMCS_sExpVLC(&instance->encbs, temp); } cnt = p_bs->bitPos & 0x7; if( cnt ) { cnt = 8 - cnt; temp = H264MCS_getBits(p_bs, cnt); NSWAVCMCS_putBits(&instance->encbs, temp, cnt); } cnt = p_bs->bitPos >> 3; while( cnt < (nal_size - 2) ) { temp = H264MCS_getBits(p_bs, 8); NSWAVCMCS_putBits(&instance->encbs, temp, 8); cnt = p_bs->bitPos >> 3; } temp = H264MCS_getBits(p_bs, 8); if( temp != 0 ) { cnt = 0; while( ( temp & 0x1) == 0 ) { cnt++; temp = temp >> 1; } cnt++; temp = temp >> 1; if( 8 - cnt ) { NSWAVCMCS_putBits(&instance->encbs, temp, (8 - cnt)); } NSWAVCMCS_putRbspTbits(&instance->encbs); } else { if( instance->encbs.bitPos % 8 ) { NSWAVCMCS_putBits(&instance->encbs, 0, (8 - instance->encbs.bitPos % 8)); } } temp = instance->encbs.byteCnt; temp = temp + 1; outbuff[outbuffpos] = (M4OSA_UInt8)(( temp >> 24) & 0xFF); outbuff[outbuffpos + 1] = (M4OSA_UInt8)(( temp >> 16) & 0xFF); outbuff[outbuffpos + 2] = (M4OSA_UInt8)(( temp >> 8) & 0xFF); outbuff[outbuffpos + 3] = (M4OSA_UInt8)((temp) &0xFF); outbuffpos = outbuffpos + temp + 4; } else { p_bs->Buffer = p_bs->Buffer - 5; memcpy((void *) &outbuff[outbuffpos], (void *)p_bs->Buffer, nal_size + 4); outbuff[outbuffpos] = (M4OSA_UInt8)((nal_size >> 24)& 0xFF); outbuff[outbuffpos + 1] = (M4OSA_UInt8)((nal_size >> 16)& 0xFF);; outbuff[outbuffpos + 2] = (M4OSA_UInt8)((nal_size >> 8)& 0xFF);; outbuff[outbuffpos + 3] = (M4OSA_UInt8)((nal_size)& 0xFF);; outbuffpos = outbuffpos + nal_size + 4; } } *outbuf_size = outbuffpos; instance->POC_lsb = instance->POC_lsb + 1; if( instance->POC_lsb == instance->POC_lsb_mod ) { instance->POC_lsb = 0; } instance->frame_count = instance->frame_count + 1; if( instance->frame_count == instance->frame_mod_count ) { instance->frame_count = 0; } return M4NO_ERROR; } M4OSA_ERR M4MCS_convetFromByteStreamtoNALStream( M4OSA_UInt8 *inbuff, M4OSA_UInt32 inbuf_size ) { M4OSA_ERR err = M4NO_ERROR; M4OSA_UInt32 framesize = 0; M4OSA_UInt32 nal_size =0; M4OSA_UInt8 *buff; while(framesize < inbuf_size) { nal_size = inbuf_size - framesize - 4; buff = inbuff + framesize + 4; while(nal_size > 4){ if((buff[0] == 0x00) && (buff[1] == 0x00) && (buff[2] == 0x00) && (buff[3] == 0x01)){ break; } buff = buff + 1; nal_size = nal_size -1; } if(nal_size <= 4){ nal_size = 0; } nal_size = (inbuf_size - framesize - 4) - nal_size; inbuff[framesize + 0] = (M4OSA_UInt8)((nal_size >> 24)& 0xFF); inbuff[framesize + 1] = (M4OSA_UInt8)((nal_size >> 16)& 0xFF); inbuff[framesize + 2] = (M4OSA_UInt8)((nal_size >> 8)& 0xFF); inbuff[framesize + 3] = (M4OSA_UInt8)((nal_size )& 0xFF); framesize += nal_size + 4; M4OSA_TRACE1_2("M4MCS_convetFromByteStreamtoNALStream framesize = %x nalsize = %x", framesize, nal_size) } return err; } M4OSA_ERR H264MCS_Freeinstance( NSWAVC_MCS_t *instance ) { M4OSA_ERR err = M4NO_ERROR; M4OSA_DEBUG_IF2((M4OSA_NULL == instance), M4ERR_PARAMETER, "H264MCS_Freeinstance: instance is M4OSA_NULL"); if( M4OSA_NULL != instance->encoder_pps.slice_group_id ) { free(instance->encoder_pps.slice_group_id); } if( M4OSA_NULL != instance->p_encoder_sps ) { free(instance->p_encoder_sps); instance->p_encoder_sps = M4OSA_NULL; } if( M4OSA_NULL != instance->p_encoder_pps ) { free(instance->p_encoder_pps); instance->p_encoder_pps = M4OSA_NULL; } if( M4OSA_NULL != instance->m_pFinalDSI ) { free(instance->m_pFinalDSI); instance->m_pFinalDSI = M4OSA_NULL; } if( M4OSA_NULL != instance ) { free(instance); instance = M4OSA_NULL; } return err; } /** ****************************************************************************** * M4OSA_ERR M4MCS_getVersion(M4_VersionInfo* pVersionInfo); * @brief Get the MCS version. * @note Can be called anytime. Do not need any context. * @param pVersionInfo (OUT) Pointer to a version info structure * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pVersionInfo is M4OSA_NULL (If Debug Level >= 2) ****************************************************************************** */ M4OSA_ERR M4MCS_getVersion( M4_VersionInfo *pVersionInfo ) { M4OSA_TRACE3_1("M4MCS_getVersion called with pVersionInfo=0x%x", pVersionInfo); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pVersionInfo), M4ERR_PARAMETER, "M4MCS_getVersion: pVersionInfo is M4OSA_NULL"); pVersionInfo->m_major = M4MCS_VERSION_MAJOR; pVersionInfo->m_minor = M4MCS_VERSION_MINOR; pVersionInfo->m_revision = M4MCS_VERSION_REVISION; /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_getVersion(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * @brief Initializes the MCS (allocates an execution context). * @note * @param pContext (OUT) Pointer on the MCS context to allocate * @param pFileReadPtrFct (IN) Pointer to OSAL file reader functions * @param pFileWritePtrFct (IN) Pointer to OSAL file writer functions * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL (If Debug Level >= 2) * @return M4ERR_ALLOC: There is no more available memory ****************************************************************************** */ M4OSA_ERR M4MCS_init( M4MCS_Context *pContext, M4OSA_FileReadPointer *pFileReadPtrFct, M4OSA_FileWriterPointer *pFileWritePtrFct ) { M4MCS_InternalContext *pC = M4OSA_NULL; M4OSA_ERR err; M4OSA_TRACE3_3( "M4MCS_init called with pContext=0x%x, pFileReadPtrFct=0x%x, pFileWritePtrFct=0x%x", pContext, pFileReadPtrFct, pFileWritePtrFct); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4MCS_init: pContext is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pFileReadPtrFct), M4ERR_PARAMETER, "M4MCS_init: pFileReadPtrFct is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pFileWritePtrFct), M4ERR_PARAMETER, "M4MCS_init: pFileWritePtrFct is M4OSA_NULL"); /** * Allocate the MCS context and return it to the user */ pC = (M4MCS_InternalContext *)M4OSA_32bitAlignedMalloc(sizeof(M4MCS_InternalContext), M4MCS, (M4OSA_Char *)"M4MCS_InternalContext"); *pContext = pC; if( M4OSA_NULL == pC ) { M4OSA_TRACE1_0( "M4MCS_init(): unable to allocate M4MCS_InternalContext, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } /** * Init the context. All pointers must be initialized to M4OSA_NULL * because CleanUp() can be called just after Init(). */ pC->State = M4MCS_kState_CREATED; pC->pOsaFileReadPtr = pFileReadPtrFct; pC->pOsaFileWritPtr = pFileWritePtrFct; pC->VideoState = M4MCS_kStreamState_NOSTREAM; pC->AudioState = M4MCS_kStreamState_NOSTREAM; pC->noaudio = M4OSA_FALSE; pC->novideo = M4OSA_FALSE; pC->uiProgress = 0; /** * Reader stuff */ pC->pInputFile = M4OSA_NULL; pC->InputFileType = M4VIDEOEDITING_kFileType_Unsupported; pC->bFileOpenedInFastMode = M4OSA_FALSE; pC->pReaderContext = M4OSA_NULL; pC->pReaderVideoStream = M4OSA_NULL; pC->pReaderAudioStream = M4OSA_NULL; pC->bUnsupportedVideoFound = M4OSA_FALSE; pC->bUnsupportedAudioFound = M4OSA_FALSE; pC->iAudioCtsOffset = 0; /* First temporary video AU to have more precise end video cut*/ pC->ReaderVideoAU1.m_structSize = 0; /* Second temporary video AU to have more precise end video cut*/ pC->ReaderVideoAU2.m_structSize = 0; pC->ReaderAudioAU1.m_structSize = 0; pC->ReaderAudioAU2.m_structSize = 0; pC->m_audioAUDuration = 0; pC->m_pDataAddress1 = M4OSA_NULL; pC->m_pDataAddress2 = M4OSA_NULL; /* First temporary video AU data to have more precise end video cut*/ pC->m_pDataVideoAddress1 = M4OSA_NULL; /* Second temporary video AU data to have more precise end video cut*/ pC->m_pDataVideoAddress2 = M4OSA_NULL; /** * Video decoder stuff */ pC->pViDecCtxt = M4OSA_NULL; pC->dViDecStartingCts = 0.0; pC->iVideoBeginDecIncr = 0; pC->dViDecCurrentCts = 0.0; pC->dCtsIncrement = 0.0; pC->isRenderDup = M4OSA_FALSE; /** * Video encoder stuff */ pC->pViEncCtxt = M4OSA_NULL; pC->pPreResizeFrame = M4OSA_NULL; pC->uiEncVideoBitrate = 0; pC->encoderState = M4MCS_kNoEncoder; /** * Audio decoder stuff */ pC->pAudioDecCtxt = M4OSA_NULL; pC->AudioDecBufferIn.m_dataAddress = M4OSA_NULL; pC->AudioDecBufferIn.m_bufferSize = 0; pC->AudioDecBufferOut.m_dataAddress = M4OSA_NULL; pC->AudioDecBufferOut.m_bufferSize = 0; pC->pPosInDecBufferOut = M4OSA_NULL; /** * Ssrc stuff */ pC->pSsrcBufferIn = M4OSA_NULL; pC->pSsrcBufferOut = M4OSA_NULL; pC->pPosInSsrcBufferIn = M4OSA_NULL; pC->pPosInSsrcBufferOut = M4OSA_NULL; pC->iSsrcNbSamplIn = 0; pC->iSsrcNbSamplOut = 0; pC->SsrcScratch = M4OSA_NULL; pC->pLVAudioResampler = M4OSA_NULL; /** * Audio encoder */ pC->pAudioEncCtxt = M4OSA_NULL; pC->pAudioEncDSI.infoSize = 0; pC->pAudioEncDSI.pInfo = M4OSA_NULL; pC->pAudioEncoderBuffer = M4OSA_NULL; pC->pPosInAudioEncoderBuffer = M4OSA_NULL; pC->audioEncoderGranularity = 0; /** * Writer stuff */ pC->pOutputFile = M4OSA_NULL; pC->pTemporaryFile = M4OSA_NULL; pC->pWriterContext = M4OSA_NULL; pC->uiVideoAUCount = 0; pC->uiVideoMaxAuSize = 0; pC->uiVideoMaxChunckSize = 0; pC->uiAudioAUCount = 0; pC->uiAudioMaxAuSize = 0; pC->uiAudioCts = 0; pC->b_isRawWriter = M4OSA_FALSE; pC->pOutputPCMfile = M4OSA_NULL; /* Encoding config */ pC->EncodingVideoFormat = M4ENCODER_kNULL; /**< No format set yet */ pC->EncodingWidth = 0; /**< No size set yet */ pC->EncodingHeight = 0; /**< No size set yet */ pC->EncodingVideoFramerate = 0; /**< No framerate set yet */ pC->uiBeginCutTime = 0; /**< No begin cut */ pC->uiEndCutTime = 0; /**< No end cut */ pC->uiMaxFileSize = 0; /**< No limit */ pC->uiAudioBitrate = M4VIDEOEDITING_kUndefinedBitrate; /**< No bitrate set yet */ pC->uiVideoBitrate = M4VIDEOEDITING_kUndefinedBitrate; /**< No bitrate set yet */ pC->WriterVideoStream.streamType = M4SYS_kVideoUnknown; pC->WriterVideoStreamInfo.Header.pBuf = M4OSA_NULL; pC->WriterAudioStream.streamType = M4SYS_kAudioUnknown; pC->outputVideoTimescale = 0; /*FB 2008/10/20: add media rendering parameter and AIR context to keep media aspect ratio*/ pC->MediaRendering = M4MCS_kResizing; pC->m_air_context = M4OSA_NULL; /**/ /** * FlB 2009.03.04: add audio Effects*/ pC->pEffects = M4OSA_NULL; pC->nbEffects = 0; pC->pActiveEffectNumber = -1; /**/ /* * Reset pointers for media and codecs interfaces */ err = M4MCS_clearInterfaceTables(pC); M4ERR_CHECK_RETURN(err); /* * Call the media and codecs subscription module */ err = M4MCS_subscribeMediaAndCodec(pC); M4ERR_CHECK_RETURN(err); #ifdef M4MCS_SUPPORT_STILL_PICTURE /** * Initialize the Still picture part of MCS*/ err = M4MCS_stillPicInit(pC, pFileReadPtrFct, pFileWritePtrFct); M4ERR_CHECK_RETURN(err); pC->m_bIsStillPicture = M4OSA_FALSE; #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ pC->m_pInstance = M4OSA_NULL; pC->H264MCSTempBuffer = M4OSA_NULL; pC->H264MCSTempBufferSize = 0; pC->H264MCSTempBufferDataSize = 0; pC->bH264Trim = M4OSA_FALSE; /* Flag to get the last decoded frame cts */ pC->bLastDecodedFrameCTS = M4OSA_FALSE; if( pC->m_pInstance == M4OSA_NULL ) { err = H264MCS_Getinstance(&pC->m_pInstance); } pC->bExtOMXAudDecoder = M4OSA_FALSE; /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_init(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_open(M4MCS_Context pContext, M4OSA_Void* pFileIn, * M4OSA_Void* pFileOut, M4OSA_Void* pTempFile); * @brief Set the MCS input and output files. * @note It opens the input file, but the output file is not created yet. * @param pContext (IN) MCS context * @param pFileIn (IN) Input file to transcode (The type of this parameter * (URL, pipe...) depends on the OSAL implementation). * @param mediaType (IN) Container type (.3gp,.amr,mp3 ...) of input file. * @param pFileOut (IN) Output file to create (The type of this parameter * (URL, pipe...) depends on the OSAL implementation). * @param pTempFile (IN) Temporary file for the constant memory writer to * store metadata ("moov.bin"). * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL (debug only) * @return M4ERR_STATE: MCS is not in an appropriate state for this function to be called * @return M4ERR_ALLOC: There is no more available memory * @return M4ERR_FILE_NOT_FOUND: The input file has not been found * @return M4MCS_ERR_INVALID_INPUT_FILE: The input file is not a valid file, or is corrupted * @return M4MCS_ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM: The input file contains no * supported audio or video stream ****************************************************************************** */ M4OSA_ERR M4MCS_open( M4MCS_Context pContext, M4OSA_Void *pFileIn, M4VIDEOEDITING_FileType InputFileType, M4OSA_Void *pFileOut, M4OSA_Void *pTempFile ) { M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); M4OSA_ERR err; M4READER_MediaFamily mediaFamily; M4_StreamHandler *pStreamHandler; M4OSA_TRACE2_3( "M4MCS_open called with pContext=0x%x, pFileIn=0x%x, pFileOut=0x%x", pContext, pFileIn, pFileOut); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4MCS_open: pContext is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pFileIn), M4ERR_PARAMETER, "M4MCS_open: pFileIn is M4OSA_NULL"); if( ( InputFileType == M4VIDEOEDITING_kFileType_JPG) || (InputFileType == M4VIDEOEDITING_kFileType_PNG) || (InputFileType == M4VIDEOEDITING_kFileType_GIF) || (InputFileType == M4VIDEOEDITING_kFileType_BMP) ) { #ifdef M4MCS_SUPPORT_STILL_PICTURE /** * Indicate that we must use the still picture functions*/ pC->m_bIsStillPicture = M4OSA_TRUE; /** * Call the still picture MCS functions*/ return M4MCS_stillPicOpen(pC, pFileIn, InputFileType, pFileOut); #else M4OSA_TRACE1_0( "M4MCS_open: Still picture is not supported with this version of MCS"); return M4MCS_ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM; #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ } /** * Check state automaton */ if( M4MCS_kState_CREATED != pC->State ) { M4OSA_TRACE1_1("M4MCS_open(): Wrong State (%d), returning M4ERR_STATE", pC->State); return M4ERR_STATE; } /* Copy function input parameters into our context */ pC->pInputFile = pFileIn; pC->InputFileType = InputFileType; pC->pOutputFile = pFileOut; pC->pTemporaryFile = pTempFile; pC->uiProgress = 0; /***********************************/ /* Open input file with the reader */ /***********************************/ err = M4MCS_setCurrentReader(pContext, pC->InputFileType); M4ERR_CHECK_RETURN(err); /** * Reset reader related variables */ pC->VideoState = M4MCS_kStreamState_NOSTREAM; pC->AudioState = M4MCS_kStreamState_NOSTREAM; pC->pReaderVideoStream = M4OSA_NULL; pC->pReaderAudioStream = M4OSA_NULL; /*******************************************************/ /* Initializes the reader shell and open the data file */ /*******************************************************/ err = pC->m_pReader->m_pFctCreate(&pC->pReaderContext); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1("M4MCS_open(): m_pReader->m_pFctCreate returns 0x%x", err); return err; } /** * Link the reader interface to the reader context */ pC->m_pReaderDataIt->m_readerContext = pC->pReaderContext; /** * Set the reader shell file access functions */ err = pC->m_pReader->m_pFctSetOption(pC->pReaderContext, M4READER_kOptionID_SetOsaFileReaderFctsPtr, (M4OSA_DataOption)pC->pOsaFileReadPtr); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1("M4MCS_open(): m_pReader->m_pFctSetOption returns 0x%x", err); return err; } #ifdef M4MCS_WITH_FAST_OPEN if( M4OSA_FALSE == pC->bFileOpenedInFastMode ) { M4OSA_Bool trueValue = M4OSA_TRUE; /* For first call use fast open mode */ err = pC->m_pReader->m_pFctSetOption(pC->pReaderContext, M4READER_3GP_kOptionID_FastOpenMode, &trueValue); if( M4NO_ERROR == err ) { pC->bFileOpenedInFastMode = M4OSA_TRUE; } else { M4OSA_TRACE1_1( "M4MCS_open(): M4READER_3GP_kOptionID_FastOpenMode returns 0x%x", err); if( ( ( (M4OSA_UInt32)M4ERR_BAD_OPTION_ID) == err) || (( (M4OSA_UInt32)M4ERR_PARAMETER) == err) ) { /* Not fatal, some readers may not support fast open mode */ pC->bFileOpenedInFastMode = M4OSA_FALSE; } else return err; } } else { M4OSA_Bool falseValue = M4OSA_FALSE; /* For second call use normal open mode */ err = pC->m_pReader->m_pFctSetOption(pC->pReaderContext, M4READER_3GP_kOptionID_FastOpenMode, &falseValue); } #endif /* M4MCS_WITH_FAST_OPEN */ /** * Open the input file */ err = pC->m_pReader->m_pFctOpen(pC->pReaderContext, pC->pInputFile); if( M4NO_ERROR != err ) { M4OSA_UInt32 uiDummy, uiCoreId; M4OSA_TRACE1_1("M4MCS_open(): m_pReader->m_pFctOpen returns 0x%x", err); /** * If the error is from the core reader, we change it to a public VXS error */ M4OSA_ERR_SPLIT(err, uiDummy, uiCoreId, uiDummy); if( M4MP4_READER == uiCoreId ) { M4OSA_TRACE1_0( "M4MCS_open(): returning M4MCS_ERR_INVALID_INPUT_FILE"); return M4MCS_ERR_INVALID_INPUT_FILE; } return err; } /** * Get the streams from the input file */ while( M4NO_ERROR == err ) { err = pC->m_pReader->m_pFctGetNextStream( pC->pReaderContext, &mediaFamily, &pStreamHandler); /** * In case we found a BIFS stream or something else...*/ if( ( err == ((M4OSA_UInt32)M4ERR_READER_UNKNOWN_STREAM_TYPE)) || (err == ((M4OSA_UInt32)M4WAR_TOO_MUCH_STREAMS)) ) { err = M4NO_ERROR; continue; } if( M4NO_ERROR == err ) /**< One stream found */ { /** * Found the first video stream */ if( ( M4READER_kMediaFamilyVideo == mediaFamily) && (M4OSA_NULL == pC->pReaderVideoStream) ) { if( ( M4DA_StreamTypeVideoH263 == pStreamHandler->m_streamType) || (M4DA_StreamTypeVideoMpeg4 == pStreamHandler->m_streamType) || (M4DA_StreamTypeVideoMpeg4Avc == pStreamHandler->m_streamType) ) { M4OSA_TRACE3_0( "M4MCS_open(): Found a H263 or MPEG-4 video stream in input 3gpp clip"); /** * Keep pointer to the video stream */ pC->pReaderVideoStream = (M4_VideoStreamHandler *)pStreamHandler; pC->bUnsupportedVideoFound = M4OSA_FALSE; pStreamHandler->m_bStreamIsOK = M4OSA_TRUE; /** * Init our video stream state variable */ pC->VideoState = M4MCS_kStreamState_STARTED; /** * Reset the stream reader */ err = pC->m_pReader->m_pFctReset(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_open():\ m_pReader->m_pFctReset(video) returns 0x%x", err); return err; } /** * Initializes an access Unit */ err = pC->m_pReader->m_pFctFillAuStruct(pC->pReaderContext, pStreamHandler, &pC->ReaderVideoAU); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_open():\ m_pReader->m_pFctFillAuStruct(video) returns 0x%x", err); return err; } } else /**< Not H263 or MPEG-4 (H264, etc.) */ { M4OSA_TRACE1_1("M4MCS_open(): Found an unsupported video stream (0x%x) in\ input 3gpp clip", pStreamHandler->m_streamType); pC->bUnsupportedVideoFound = M4OSA_TRUE; pStreamHandler->m_bStreamIsOK = M4OSA_FALSE; } /* +CRLV6775 -H.264 Trimming */ if( M4DA_StreamTypeVideoMpeg4Avc == pStreamHandler->m_streamType ) { // SPS and PPS are storead as per the 3gp file format pC->m_pInstance->m_pDecoderSpecificInfo = pStreamHandler->m_pH264DecoderSpecificInfo; pC->m_pInstance->m_decoderSpecificInfoSize = pStreamHandler->m_H264decoderSpecificInfoSize; } /* -CRLV6775 -H.264 Trimming */ } /** * Found the first audio stream */ else if( ( M4READER_kMediaFamilyAudio == mediaFamily) && (M4OSA_NULL == pC->pReaderAudioStream) ) { if( ( M4DA_StreamTypeAudioAmrNarrowBand == pStreamHandler->m_streamType) || (M4DA_StreamTypeAudioAac == pStreamHandler->m_streamType) || (M4DA_StreamTypeAudioMp3 == pStreamHandler->m_streamType) || (M4DA_StreamTypeAudioEvrc == pStreamHandler->m_streamType) ) { M4OSA_TRACE3_0( "M4MCS_open(): Found an AMR-NB, AAC or MP3 audio stream in input clip"); /** * Keep pointer to the audio stream */ pC->pReaderAudioStream = (M4_AudioStreamHandler *)pStreamHandler; pStreamHandler->m_bStreamIsOK = M4OSA_TRUE; pC->bUnsupportedAudioFound = M4OSA_FALSE; /** * Init our audio stream state variable */ pC->AudioState = M4MCS_kStreamState_STARTED; /** * Reset the stream reader */ err = pC->m_pReader->m_pFctReset(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderAudioStream); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_open():\ m_pReader->m_pFctReset(audio) returns 0x%x", err); return err; } /** * Initializes an access Unit */ err = pC->m_pReader->m_pFctFillAuStruct(pC->pReaderContext, pStreamHandler, &pC->ReaderAudioAU); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_open():\ m_pReader->m_pFctFillAuStruct(audio) returns 0x%x", err); return err; } /** * Output max AU size is equal to input max AU size (this value * will be changed if there is audio transcoding) */ pC->uiAudioMaxAuSize = pStreamHandler->m_maxAUSize; } else { /**< Not AMR-NB, AAC, MP3 nor EVRC (AMR-WB, WAV...) */ M4OSA_TRACE1_1("M4MCS_open(): Found an unsupported audio stream (0x%x) in \ input 3gpp clip", pStreamHandler->m_streamType); pC->bUnsupportedAudioFound = M4OSA_TRUE; pStreamHandler->m_bStreamIsOK = M4OSA_FALSE; } } } } /**< end of while (M4NO_ERROR == err) */ /** * Check we found at least one supported stream */ if( ( M4OSA_NULL == pC->pReaderVideoStream) && (M4OSA_NULL == pC->pReaderAudioStream) ) { M4OSA_TRACE1_0( "M4MCS_open(): returning M4MCS_ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM"); return M4MCS_ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM; } if( pC->VideoState == M4MCS_kStreamState_STARTED ) { err = M4MCS_setCurrentVideoDecoder(pContext, pC->pReaderVideoStream->m_basicProperties.m_streamType); /*FB 2009-02-09: the error is check and returned only if video codecs are compiled, else only audio is used, that is why the editing process can continue*/ #ifndef M4MCS_AUDIOONLY M4ERR_CHECK_RETURN(err); #else if( ( M4NO_ERROR != err) && (M4MCS_WAR_MEDIATYPE_NOT_SUPPORTED != err) ) { M4ERR_CHECK_RETURN(err); } #endif /*M4MCS_AUDIOONLY*/ } if( pC->AudioState == M4MCS_kStreamState_STARTED ) { //EVRC if( M4DA_StreamTypeAudioEvrc != pStreamHandler-> m_streamType ) /* decoder not supported yet, but allow to do null encoding */ { err = M4MCS_setCurrentAudioDecoder(pContext, pC->pReaderAudioStream->m_basicProperties.m_streamType); M4ERR_CHECK_RETURN(err); } } /** * Get the audio and video stream properties */ err = M4MCS_intGetInputClipProperties(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_open(): M4MCS_intGetInputClipProperties returns 0x%x", err); return err; } /** * Set the begin cut decoding increment according to the input frame rate */ if( 0. != pC->InputFileProperties.fAverageFrameRate ) /**< sanity check */ { pC->iVideoBeginDecIncr = (M4OSA_Int32)(3000. / pC->InputFileProperties. fAverageFrameRate); /**< about 3 frames */ } else { pC->iVideoBeginDecIncr = 200; /**< default value: 200 milliseconds (3 frames @ 15fps)*/ } /** * Update state automaton */ pC->State = M4MCS_kState_OPENED; /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_open(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_step(M4MCS_Context pContext, M4OSA_UInt8 *pProgress); * @brief Perform one step of trancoding. * @note * @param pContext (IN) MCS context * @param pProgress (OUT) Progress percentage (0 to 100) of the transcoding * @note pProgress must be a valid address. * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: One of the parameters is M4OSA_NULL (debug only) * @return M4ERR_STATE: MCS is not in an appropriate state for this function to be called * @return M4MCS_WAR_TRANSCODING_DONE: Transcoding is over, user should now call M4MCS_close() * @return M4MCS_ERR_AUDIO_CONVERSION_FAILED: The audio conversion (AAC to AMR-NB or MP3) failed * @return M4MCS_ERR_INVALID_AAC_SAMPLING_FREQUENCY: The input file contains an AAC audio track * with an invalid sampling frequency (should never happen) ****************************************************************************** */ M4OSA_ERR M4MCS_step( M4MCS_Context pContext, M4OSA_UInt8 *pProgress ) { M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); M4OSA_TRACE3_1("M4MCS_step called with pContext=0x%x", pContext); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4MCS_step: pContext is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pProgress), M4ERR_PARAMETER, "M4MCS_step: pProgress is M4OSA_NULL"); #ifdef M4MCS_SUPPORT_STILL_PICTURE if( pC->m_bIsStillPicture ) { /** * Call the still picture MCS functions*/ return M4MCS_stillPicStep(pC, pProgress); } #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ /** * Check state automaton */ switch( pC->State ) { case M4MCS_kState_READY: *pProgress = 0; return M4MCS_intStepSet(pC); break; case M4MCS_kState_BEGINVIDEOJUMP: *pProgress = pC->uiProgress; return M4MCS_intStepBeginVideoJump(pC); break; case M4MCS_kState_BEGINVIDEODECODE: *pProgress = pC->uiProgress; return M4MCS_intStepBeginVideoDecode(pC); break; case M4MCS_kState_PROCESSING: { M4OSA_ERR err = M4NO_ERROR; err = M4MCS_intStepEncoding(pC, pProgress); /* Save progress info in case of pause */ pC->uiProgress = *pProgress; return err; } break; default: /**< State error */ M4OSA_TRACE1_1( "M4MCS_step(): Wrong State (%d), returning M4ERR_STATE", pC->State); return M4ERR_STATE; } } /** ****************************************************************************** * M4OSA_ERR M4MCS_pause(M4MCS_Context pContext); * @brief Pause the transcoding i.e. release the (external hardware) video decoder. * @note This function is not needed if no hardware accelerators are used. * In that case, pausing the MCS is simply achieved by temporarily suspending * the M4MCS_step function calls. * @param pContext (IN) MCS context * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only) * @return M4ERR_STATE: MCS is not in an appropriate state for this function to be called ****************************************************************************** */ M4OSA_ERR M4MCS_pause( M4MCS_Context pContext ) { M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); M4OSA_ERR err; M4OSA_TRACE2_1("M4MCS_pause called with pContext=0x%x", pContext); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4MCS_pause: pContext is M4OSA_NULL"); #ifdef M4MCS_SUPPORT_STILL_PICTURE if( pC->m_bIsStillPicture ) { /** * Call the corresponding still picture MCS function*/ return M4MCS_stillPicPause(pC); } #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ /** * Check state automaton */ switch( pC->State ) { case M4MCS_kState_BEGINVIDEOJUMP: /**< the video decoder has been created, we must destroy it */ case M4MCS_kState_BEGINVIDEODECODE: /**< the video is being used, we must destroy it */ case M4MCS_kState_PROCESSING: /**< the video is being used, we must destroy it */ /**< OK, nothing to do here */ break; default: /**< State error */ M4OSA_TRACE1_1( "M4MCS_pause(): Wrong State (%d), returning M4ERR_STATE", pC->State); return M4ERR_STATE; } /** * Set the CTS at which we will resume the decoding */ if( pC->dViDecCurrentCts > pC->dViDecStartingCts ) { /** * We passed the starting CTS, so the resume target is the current CTS */ pC->dViDecStartingCts = pC->dViDecCurrentCts; } else { /** * We haven't passed the starting CTS yet, so the resume target is still the starting CTS * --> nothing to do in the else block */ } /** * Free video decoder stuff */ if( M4OSA_NULL != pC->pViDecCtxt ) { err = pC->m_pVideoDecoder->m_pFctDestroy(pC->pViDecCtxt); pC->pViDecCtxt = M4OSA_NULL; if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_pause: m_pVideoDecoder->pFctDestroy returns 0x%x", err); return err; } } /** * State transition */ pC->State = M4MCS_kState_PAUSED; M4OSA_TRACE3_0("M4MCS_pause(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_resume(M4MCS_Context pContext); * @brief Resume the transcoding after a pause (see M4MCS_pause). * @note This function is not needed if no hardware accelerators are used. * In that case, resuming the MCS is simply achieved by calling * the M4MCS_step function. * @param pContext (IN) MCS context * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only) * @return M4ERR_STATE: MCS is not in an appropriate state for this function to be called ****************************************************************************** */ M4OSA_ERR M4MCS_resume( M4MCS_Context pContext ) { M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); M4OSA_ERR err; M4OSA_TRACE2_1("M4MCS_resume called with pContext=0x%x", pContext); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4MCS_resume: pContext is M4OSA_NULL"); #ifdef M4MCS_SUPPORT_STILL_PICTURE if( pC->m_bIsStillPicture ) { /** * Call the corresponding still picture MCS function*/ return M4MCS_stillPicResume(pC); } #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ /** * Check state automaton */ switch( pC->State ) { case M4MCS_kState_PAUSED: /**< OK, nothing to do here */ break; default: /**< State error */ M4OSA_TRACE1_1( "M4MCS_resume(): Wrong State (%d), returning M4ERR_STATE", pC->State); return M4ERR_STATE; break; } /** * Prepare the video decoder */ err = M4MCS_intPrepareVideoDecoder(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_resume(): M4MCS_intPrepareVideoDecoder() returns 0x%x", err); return err; } /** * State transition */ if( 0.0 == pC->dViDecStartingCts ) { /** * We are still at the beginning of the decoded stream, no need to jump, we can proceed */ pC->State = M4MCS_kState_PROCESSING; } else { /** * Jumping */ pC->State = M4MCS_kState_BEGINVIDEOJUMP; } M4OSA_TRACE3_0("M4MCS_resume(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_close(M4MCS_Context pContext); * @brief Finish the MCS transcoding. * @note The output 3GPP file is ready to be played after this call * @param pContext (IN) MCS context * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (If Debug Level >= 2) * @return M4ERR_STATE: MCS is not in an appropriate state for this function to be called ****************************************************************************** */ M4OSA_ERR M4MCS_close( M4MCS_Context pContext ) { M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); M4ENCODER_Header *encHeader; M4SYS_StreamIDmemAddr streamHeader; M4OSA_ERR err = M4NO_ERROR, err2; M4OSA_TRACE2_1("M4MCS_close called with pContext=0x%x", pContext); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4MCS_close: pContext is M4OSA_NULL"); #ifdef M4MCS_SUPPORT_STILL_PICTURE if( pC->m_bIsStillPicture ) { /** * Indicate that current file is no longer a still picture*/ pC->m_bIsStillPicture = M4OSA_FALSE; /** * Call the corresponding still picture MCS function*/ return M4MCS_stillPicClose(pC); } #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ /** * Check state automaton */ if( M4MCS_kState_FINISHED != pC->State ) { M4OSA_TRACE1_1("M4MCS_close(): Wrong State (%d), returning M4ERR_STATE", pC->State); return M4ERR_STATE; } /* Close the encoder before the writer to be certain all the AUs have been written and we can get the DSI. */ /* Has the encoder actually been started? Don't stop it if that's not the case. */ if( M4MCS_kEncoderRunning == pC->encoderState ) { if( pC->pVideoEncoderGlobalFcts->pFctStop != M4OSA_NULL ) { err = pC->pVideoEncoderGlobalFcts->pFctStop(pC->pViEncCtxt); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_close: pVideoEncoderGlobalFcts->pFctStop returns 0x%x", err); /* Well... how the heck do you handle a failed cleanup? */ } } pC->encoderState = M4MCS_kEncoderStopped; } /* Has the encoder actually been opened? Don't close it if that's not the case. */ if( M4MCS_kEncoderStopped == pC->encoderState ) { err = pC->pVideoEncoderGlobalFcts->pFctClose(pC->pViEncCtxt); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_close: pVideoEncoderGlobalFcts->pFctClose returns 0x%x", err); /* Well... how the heck do you handle a failed cleanup? */ } pC->encoderState = M4MCS_kEncoderClosed; } /**********************************/ /******** Close the writer ********/ /**********************************/ if( M4OSA_NULL != pC->pWriterContext ) /* happens in state _SET */ { /* HW encoder: fetch the DSI from the shell video encoder, and feed it to the writer before closing it. */ if( pC->novideo != M4OSA_TRUE ) { if( ( M4ENCODER_kMPEG4 == pC->EncodingVideoFormat) || (M4ENCODER_kH264 == pC->EncodingVideoFormat) ) { err = pC->pVideoEncoderGlobalFcts->pFctGetOption(pC->pViEncCtxt, M4ENCODER_kOptionID_EncoderHeader, (M4OSA_DataOption) &encHeader); if( ( M4NO_ERROR != err) || (M4OSA_NULL == encHeader->pBuf) ) { M4OSA_TRACE1_1( "M4MCS_close: failed to get the encoder header (err 0x%x)", err); /**< no return here, we still have stuff to deallocate after close, even if it fails. */ } else { /* set this header in the writer */ streamHeader.streamID = M4MCS_WRITER_VIDEO_STREAM_ID; streamHeader.size = encHeader->Size; streamHeader.addr = (M4OSA_MemAddr32)encHeader->pBuf; } M4OSA_TRACE1_0("calling set option"); err = pC->pWriterGlobalFcts->pFctSetOption(pC->pWriterContext, M4WRITER_kDSI, &streamHeader); M4OSA_TRACE1_0("set option done"); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_close: failed to set the DSI in the writer (err 0x%x)", err); } } if( ( M4OSA_TRUE == pC->bH264Trim) && (M4ENCODER_kNULL == pC->EncodingVideoFormat) ) { if(pC->uiBeginCutTime == 0) { M4OSA_TRACE1_1("Decoder specific info size = %d", pC->m_pInstance->m_decoderSpecificInfoSize); pC->m_pInstance->m_pFinalDSISize = pC->m_pInstance->m_decoderSpecificInfoSize; M4OSA_TRACE1_1("Decoder specific info pointer = %d", (M4OSA_MemAddr8)pC->m_pInstance->m_pDecoderSpecificInfo); pC->m_pInstance->m_pFinalDSI = (M4OSA_UInt8 *)M4OSA_32bitAlignedMalloc(pC->m_pInstance-> \ m_decoderSpecificInfoSize, M4MCS, (M4OSA_Char *)"instance->m_pFinalDSI"); if( pC->m_pInstance->m_pFinalDSI == M4OSA_NULL ) { M4OSA_TRACE1_0("instance->m_pFinalDSI: allocation error"); return M4ERR_ALLOC; } memcpy((void *)pC->m_pInstance->m_pFinalDSI, (void *)pC-> \ m_pInstance->m_pDecoderSpecificInfo, pC->m_pInstance->m_decoderSpecificInfoSize); } streamHeader.streamID = M4MCS_WRITER_VIDEO_STREAM_ID; streamHeader.size = pC->m_pInstance->m_pFinalDSISize; streamHeader.addr = (M4OSA_MemAddr32)pC->m_pInstance->m_pFinalDSI; M4OSA_TRACE1_0("calling set option"); err = pC->pWriterGlobalFcts->pFctSetOption(pC->pWriterContext, M4WRITER_kDSI, &streamHeader); M4OSA_TRACE1_0("set option done"); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_close: failed to set the DSI in the writer (err 0x%x)", err); } } } /* Write and close the 3GP output file */ err2 = pC->pWriterGlobalFcts->pFctCloseWrite(pC->pWriterContext); pC->pWriterContext = M4OSA_NULL; if( M4NO_ERROR != err2 ) { M4OSA_TRACE1_1( "M4MCS_close: pWriterGlobalFcts->pFctCloseWrite returns 0x%x", err2); if( M4NO_ERROR == err ) err = err2; /**< no return here, we still have stuff to deallocate after close, even if it fails.*/ } } /* Close output PCM file if needed */ if( pC->pOutputPCMfile != M4OSA_NULL ) { pC->pOsaFileWritPtr->closeWrite(pC->pOutputPCMfile); pC->pOutputPCMfile = M4OSA_NULL; } /*FlB 2009.03.04: add audio effects, free effects list*/ if( M4OSA_NULL != pC->pEffects ) { free(pC->pEffects); pC->pEffects = M4OSA_NULL; } pC->nbEffects = 0; pC->pActiveEffectNumber = -1; /** * State transition */ pC->State = M4MCS_kState_CLOSED; if( M4OSA_NULL != pC->H264MCSTempBuffer ) { free(pC->H264MCSTempBuffer); } M4OSA_TRACE3_0("M4MCS_close(): returning M4NO_ERROR"); return err; } /** ****************************************************************************** * M4OSA_ERR M4MCS_cleanUp(M4MCS_Context pContext); * @brief Free all resources used by the MCS. * @note The context is no more valid after this call * @param pContext (IN) MCS context * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (If Debug Level >= 2) * @return M4ERR_STATE: MCS is not in an appropriate state for this function to be called ****************************************************************************** */ M4OSA_ERR M4MCS_cleanUp( M4MCS_Context pContext ) { M4OSA_ERR err = M4NO_ERROR; M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); M4OSA_TRACE3_1("M4MCS_cleanUp called with pContext=0x%x", pContext); #ifdef MCS_DUMP_PCM_TO_FILE if( file_au_reader ) { fclose(file_au_reader); file_au_reader = NULL; } if( file_pcm_decoder ) { fclose(file_pcm_decoder); file_pcm_decoder = NULL; } if( file_pcm_encoder ) { fclose(file_pcm_encoder); file_pcm_encoder = NULL; } #endif /** * Check input parameter */ if( M4OSA_NULL == pContext ) { M4OSA_TRACE1_0( "M4MCS_cleanUp: pContext is M4OSA_NULL, returning M4ERR_PARAMETER"); return M4ERR_PARAMETER; } /** * Check state automaton */ if( M4MCS_kState_CLOSED != pC->State ) { M4OSA_TRACE1_1( "M4MCS_cleanUp(): Wrong State (%d), returning M4ERR_STATE", pC->State); return M4ERR_STATE; } if( M4OSA_NULL != pC->m_pInstance ) { err = H264MCS_Freeinstance(pC->m_pInstance); pC->m_pInstance = M4OSA_NULL; } /* ----- Free video encoder stuff, if needed ----- */ if( ( M4OSA_NULL != pC->pViEncCtxt) && (M4OSA_NULL != pC->pVideoEncoderGlobalFcts) ) { err = pC->pVideoEncoderGlobalFcts->pFctCleanup(pC->pViEncCtxt); pC->pViEncCtxt = M4OSA_NULL; if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_cleanUp: pVideoEncoderGlobalFcts->pFctCleanup returns 0x%x", err); /**< don't return, we still have stuff to free */ } pC->encoderState = M4MCS_kNoEncoder; } /** * In the H263 case, we allocated our own DSI buffer */ if( ( M4ENCODER_kH263 == pC->EncodingVideoFormat) && (M4OSA_NULL != pC->WriterVideoStreamInfo.Header.pBuf) ) { free(pC->WriterVideoStreamInfo.Header.pBuf); pC->WriterVideoStreamInfo.Header.pBuf = M4OSA_NULL; } if( M4OSA_NULL != pC->pPreResizeFrame ) { if( M4OSA_NULL != pC->pPreResizeFrame[0].pac_data ) { free(pC->pPreResizeFrame[0].pac_data); pC->pPreResizeFrame[0].pac_data = M4OSA_NULL; } if( M4OSA_NULL != pC->pPreResizeFrame[1].pac_data ) { free(pC->pPreResizeFrame[1].pac_data); pC->pPreResizeFrame[1].pac_data = M4OSA_NULL; } if( M4OSA_NULL != pC->pPreResizeFrame[2].pac_data ) { free(pC->pPreResizeFrame[2].pac_data); pC->pPreResizeFrame[2].pac_data = M4OSA_NULL; } free(pC->pPreResizeFrame); pC->pPreResizeFrame = 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 ) { free(pC->pSsrcBufferOut); pC->pSsrcBufferOut = M4OSA_NULL; } if (pC->pLVAudioResampler != M4OSA_NULL) { LVDestroy(pC->pLVAudioResampler); pC->pLVAudioResampler = M4OSA_NULL; } /* ----- Free the audio encoder stuff ----- */ if( M4OSA_NULL != pC->pAudioEncCtxt ) { err = pC->pAudioEncoderGlobalFcts->pFctClose(pC->pAudioEncCtxt); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_cleanUp: pAudioEncoderGlobalFcts->pFctClose returns 0x%x", err); /**< don't return, we still have stuff to free */ } err = pC->pAudioEncoderGlobalFcts->pFctCleanUp(pC->pAudioEncCtxt); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_cleanUp: pAudioEncoderGlobalFcts->pFctCleanUp returns 0x%x", err); /**< don't return, we still have stuff to free */ } pC->pAudioEncCtxt = M4OSA_NULL; } if( M4OSA_NULL != pC->pAudioEncoderBuffer ) { free(pC->pAudioEncoderBuffer); pC->pAudioEncoderBuffer = M4OSA_NULL; } /* ----- Free all other stuff ----- */ /** * Free the readers and the decoders */ M4MCS_intCleanUp_ReadersDecoders(pC); #ifdef M4MCS_SUPPORT_STILL_PICTURE /** * Free the still picture resources */ M4MCS_stillPicCleanUp(pC); #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ /** * Free the shells interfaces */ M4MCS_unRegisterAllWriters(pContext); M4MCS_unRegisterAllEncoders(pContext); M4MCS_unRegisterAllReaders(pContext); M4MCS_unRegisterAllDecoders(pContext); /** * Free the context itself */ free(pC); pC = M4OSA_NULL; M4OSA_TRACE3_0("M4MCS_cleanUp(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_abort(M4MCS_Context pContext); * @brief Finish the MCS transcoding and free all resources used by the MCS * whatever the state is. * @note The context is no more valid after this call * @param pContext (IN) MCS context * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only) ****************************************************************************** */ M4OSA_ERR M4MCS_abort( M4MCS_Context pContext ) { M4OSA_ERR err = M4NO_ERROR; M4OSA_ERR err1 = M4NO_ERROR; M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); if( M4OSA_NULL == pContext ) { return M4NO_ERROR; } if( ( pC->State == M4MCS_kState_CREATED) || (pC->State == M4MCS_kState_CLOSED) ) { pC->State = M4MCS_kState_CLOSED; err = M4MCS_cleanUp(pContext); if( err != M4NO_ERROR ) { M4OSA_TRACE1_1("M4MCS_abort : M4MCS_cleanUp fails err = 0x%x", err); } } else { #ifdef M4MCS_SUPPORT_STILL_PICTURE if( pC->m_bIsStillPicture ) { /** * Cancel the ongoing processes if any*/ err = M4MCS_stillPicCancel(pC); if( err != M4NO_ERROR ) { M4OSA_TRACE1_1( "M4MCS_abort : M4MCS_stillPicCancel fails err = 0x%x", err); } /*Still picture process is now stopped; Carry on with close and cleanup*/ } #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ pC->State = M4MCS_kState_FINISHED; err = M4MCS_close(pContext); if( err != M4NO_ERROR ) { M4OSA_TRACE1_1("M4MCS_abort : M4MCS_close fails err = 0x%x", err); err1 = err; } err = M4MCS_cleanUp(pContext); if( err != M4NO_ERROR ) { M4OSA_TRACE1_1("M4MCS_abort : M4MCS_cleanUp fails err = 0x%x", err); } } err = (err1 == M4NO_ERROR) ? err : err1; return err; } /** ****************************************************************************** * M4OSA_ERR M4MCS_getInputFileProperties(M4MCS_Context pContext, * M4VIDEOEDITING_ClipProperties* pFileProperties); * @brief Retrieves the properties of the audio and video streams from the input file. * @param pContext (IN) MCS context * @param pProperties (OUT) Pointer on an allocated M4VIDEOEDITING_ClipProperties structure which is filled with the input stream properties. * @note The structure pProperties must be allocated and further de-allocated by the application. The function must be called in the opened state. * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL * @return M4ERR_STATE: MCS is not in an appropriate state for this function to be called ****************************************************************************** */ M4OSA_ERR M4MCS_getInputFileProperties( M4MCS_Context pContext, M4VIDEOEDITING_ClipProperties *pFileProperties ) { M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); M4OSA_TRACE2_2("M4MCS_getInputFileProperties called with pContext=0x%x, \ pFileProperties=0x%x", pContext, pFileProperties); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4MCS_getInputFileProperties: pContext is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pFileProperties), M4ERR_PARAMETER, "M4MCS_getInputFileProperties: pProperties is M4OSA_NULL"); #ifdef M4MCS_SUPPORT_STILL_PICTURE if( pC->m_bIsStillPicture ) { /** * Call the corresponding still picture MCS function*/ return M4MCS_stillPicGetInputFileProperties(pC, pFileProperties); } #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ /** * Check state automaton */ if( M4MCS_kState_OPENED != pC->State ) { M4OSA_TRACE1_1( "M4MCS_getInputFileProperties(): Wrong State (%d), returning M4ERR_STATE", pC->State); return M4ERR_STATE; } /** * Copy previously computed properties into given structure */ memcpy((void *)pFileProperties, (void *) &pC->InputFileProperties, sizeof(M4VIDEOEDITING_ClipProperties)); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_setOutputParams(M4MCS_Context pContext, M4MCS_OutputParams* pParams); * @brief Set the MCS video output parameters. * @note Must be called after M4MCS_open. Must be called before M4MCS_step. * @param pContext (IN) MCS context * @param pParams (IN/OUT) Transcoding parameters * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL (debug only) * @return M4ERR_STATE: MCS is not in an appropriate state for this function to be called * @return M4MCS_ERR_INVALID_VIDEO_FRAME_SIZE_FOR_H263 : Output video frame size parameter is * incompatible with H263 encoding * @return M4MCS_ERR_INVALID_VIDEO_FRAME_RATE_FOR_H263 : Output video frame size parameter is * incompatible with H263 encoding * @return M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FORMAT : Undefined output video format parameter * @return M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE : Undefined output video frame size * @return M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_RATE : Undefined output video frame rate * @return M4MCS_ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT : Undefined output audio format parameter * @return M4MCS_ERR_DURATION_IS_NULL : Specified output parameters define a null duration stream * (no audio and video) ****************************************************************************** */ M4OSA_ERR M4MCS_setOutputParams( M4MCS_Context pContext, M4MCS_OutputParams *pParams ) { M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); M4OSA_UInt32 uiFrameWidth; M4OSA_UInt32 uiFrameHeight; M4OSA_ERR err; M4OSA_TRACE2_2( "M4MCS_setOutputParams called with pContext=0x%x, pParams=0x%x", pContext, pParams); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4MCS_setOutputParams: pContext is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pParams), M4ERR_PARAMETER, "M4MCS_setOutputParams: pParam is M4OSA_NULL"); #ifdef M4MCS_SUPPORT_STILL_PICTURE if( pC->m_bIsStillPicture ) { /** * Call the corresponding still picture MCS function*/ return M4MCS_stillPicSetOutputParams(pC, pParams); } #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ /** * Check state automaton */ if( M4MCS_kState_OPENED != pC->State ) { M4OSA_TRACE1_1( "M4MCS_setOutputParams(): Wrong State (%d), returning M4ERR_STATE", pC->State); return M4ERR_STATE; } /* Ignore audio or video stream if the output do not need it, */ /* or if the input file does not have any audio or video stream */ /*FlB 26.02.2009: add mp3 as mcs output format*/ if( ( pParams->OutputVideoFormat == M4VIDEOEDITING_kNoneVideo) || (pC->VideoState == M4MCS_kStreamState_NOSTREAM) || (pParams->OutputFileType == M4VIDEOEDITING_kFileType_AMR) || (pParams->OutputFileType == M4VIDEOEDITING_kFileType_MP3) ) { pC->novideo = M4OSA_TRUE; } if( ( pParams->OutputAudioFormat == M4VIDEOEDITING_kNoneAudio) || (pC->AudioState == M4MCS_kStreamState_NOSTREAM) ) { pC->noaudio = M4OSA_TRUE; } if( pC->noaudio && pC->novideo ) { M4OSA_TRACE1_0( "!!! M4MCS_setOutputParams : clip is NULL, there is no audio, no video"); return M4MCS_ERR_DURATION_IS_NULL; } /* Set writer */ err = M4MCS_setCurrentWriter(pContext, pParams->OutputFileType); M4ERR_CHECK_RETURN(err); /* Set video parameters */ if( pC->novideo == M4OSA_FALSE ) { /** * Check Video Format correctness */ switch( pParams->OutputVideoFormat ) { case M4VIDEOEDITING_kH263: if( pParams->OutputFileType == M4VIDEOEDITING_kFileType_MP4 ) return M4MCS_ERR_H263_FORBIDDEN_IN_MP4_FILE; pC->EncodingVideoFormat = M4ENCODER_kH263; err = M4MCS_setCurrentVideoEncoder(pContext, pParams->OutputVideoFormat); M4ERR_CHECK_RETURN(err); break; case M4VIDEOEDITING_kMPEG4: pC->EncodingVideoFormat = M4ENCODER_kMPEG4; err = M4MCS_setCurrentVideoEncoder(pContext, pParams->OutputVideoFormat); M4ERR_CHECK_RETURN(err); break; case M4VIDEOEDITING_kH264: pC->EncodingVideoFormat = M4ENCODER_kH264; err = M4MCS_setCurrentVideoEncoder(pContext, pParams->OutputVideoFormat); M4ERR_CHECK_RETURN(err); break; case M4VIDEOEDITING_kNullVideo: if( ( pParams->OutputFileType == M4VIDEOEDITING_kFileType_MP4) && (pC->InputFileProperties.VideoStreamType == M4VIDEOEDITING_kH263) ) return M4MCS_ERR_H263_FORBIDDEN_IN_MP4_FILE; /* Encoder needed for begin cut to generate an I-frame */ pC->EncodingVideoFormat = M4ENCODER_kNULL; err = M4MCS_setCurrentVideoEncoder(pContext, pC->InputFileProperties.VideoStreamType); M4ERR_CHECK_RETURN(err); break; default: M4OSA_TRACE1_1("M4MCS_setOutputParams: Undefined output video format (%d),\ returning M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FORMAT", pParams->OutputVideoFormat); return M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FORMAT; } /** * Check Video frame size correctness */ if( M4VIDEOEDITING_kNullVideo == pParams->OutputVideoFormat ) { uiFrameWidth = pC->EncodingWidth = pC->InputFileProperties.uiVideoWidth; uiFrameHeight = pC->EncodingHeight = pC->InputFileProperties.uiVideoHeight; /** * Set output video profile and level */ pC->encodingVideoProfile = pC->InputFileProperties.uiVideoProfile; /** Set the target video level, because input 3gp file may * have wrong video level value (some encoders do not respect * level restrictions like video resolution when content is created). **/ pC->encodingVideoLevel = pParams->outputVideoLevel; // Clip's original width and height may not be // multiple of 16. // Ensure encoding width and height are multiple of 16 uint32_t remainder = pC->EncodingWidth % 16; if (remainder != 0) { if (remainder >= 8) { // Roll forward pC->EncodingWidth = pC->EncodingWidth + (16-remainder); } else { // Roll backward pC->EncodingWidth = pC->EncodingWidth - remainder; } uiFrameWidth = pC->EncodingWidth; } remainder = pC->EncodingHeight % 16; if (remainder != 0) { if (remainder >= 8) { // Roll forward pC->EncodingHeight = pC->EncodingHeight + (16-remainder); } else { // Roll backward pC->EncodingHeight = pC->EncodingHeight - remainder; } uiFrameHeight = pC->EncodingHeight; } } else { /** * Set output video profile and level */ pC->encodingVideoProfile = pParams->outputVideoProfile; pC->encodingVideoLevel = pParams->outputVideoLevel; switch( pParams->OutputVideoFrameSize ) { case M4VIDEOEDITING_kSQCIF: uiFrameWidth = pC->EncodingWidth = M4ENCODER_SQCIF_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_SQCIF_Height; break; case M4VIDEOEDITING_kQQVGA: uiFrameWidth = pC->EncodingWidth = M4ENCODER_QQVGA_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_QQVGA_Height; break; case M4VIDEOEDITING_kQCIF: uiFrameWidth = pC->EncodingWidth = M4ENCODER_QCIF_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_QCIF_Height; break; case M4VIDEOEDITING_kQVGA: uiFrameWidth = pC->EncodingWidth = M4ENCODER_QVGA_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_QVGA_Height; break; case M4VIDEOEDITING_kCIF: uiFrameWidth = pC->EncodingWidth = M4ENCODER_CIF_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_CIF_Height; break; case M4VIDEOEDITING_kVGA: uiFrameWidth = pC->EncodingWidth = M4ENCODER_VGA_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_VGA_Height; break; /* +PR LV5807 */ case M4VIDEOEDITING_kWVGA: uiFrameWidth = pC->EncodingWidth = M4ENCODER_WVGA_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_WVGA_Height; break; case M4VIDEOEDITING_kNTSC: uiFrameWidth = pC->EncodingWidth = M4ENCODER_NTSC_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_NTSC_Height; break; /* -PR LV5807*/ /* +CR Google */ case M4VIDEOEDITING_k640_360: uiFrameWidth = pC->EncodingWidth = M4ENCODER_640_360_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_640_360_Height; break; case M4VIDEOEDITING_k854_480: uiFrameWidth = pC->EncodingWidth = M4ENCODER_854_480_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_854_480_Height; break; case M4VIDEOEDITING_k1280_720: uiFrameWidth = pC->EncodingWidth = M4ENCODER_1280_720_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_1280_720_Height; break; case M4VIDEOEDITING_k1080_720: uiFrameWidth = pC->EncodingWidth = M4ENCODER_1080_720_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_1080_720_Height; break; case M4VIDEOEDITING_k960_720: uiFrameWidth = pC->EncodingWidth = M4ENCODER_960_720_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_960_720_Height; break; case M4VIDEOEDITING_k1920_1080: uiFrameWidth = pC->EncodingWidth = M4ENCODER_1920_1080_Width; uiFrameHeight = pC->EncodingHeight = M4ENCODER_1920_1080_Height; break; /* -CR Google */ default: M4OSA_TRACE1_1( "M4MCS_setOutputParams: Undefined output video frame size \ (%d), returning M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE", pParams->OutputVideoFrameSize); return M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE; } } /** * Compute video max au size and max chunck size. * We do it here because it depends on the frame size only, and * because we need it for the file size/video bitrate estimations */ pC->uiVideoMaxAuSize = (M4OSA_UInt32)(1.5F *(M4OSA_Float)(uiFrameWidth * uiFrameHeight) \ *M4MCS_VIDEO_MIN_COMPRESSION_RATIO); pC->uiVideoMaxChunckSize = (M4OSA_UInt32)(pC->uiVideoMaxAuSize \ * M4MCS_VIDEO_CHUNK_AU_SIZE_RATIO); /**< from max AU size to max Chunck size */ if( 0 == pC->uiVideoMaxAuSize ) { /* Size may be zero in case of null encoding with unrecognized stream */ M4OSA_TRACE1_0("M4MCS_setOutputParams: video frame size is 0 returning\ M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE"); return M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE; } /** * Size check for H263 (only valid sizes are CIF, QCIF and SQCIF) */ if( M4VIDEOEDITING_kH263 == pParams->OutputVideoFormat ) { switch( pParams->OutputVideoFrameSize ) { case M4VIDEOEDITING_kSQCIF: case M4VIDEOEDITING_kQCIF: case M4VIDEOEDITING_kCIF: /* OK */ break; default: M4OSA_TRACE1_0( "M4MCS_setOutputParams():\ returning M4MCS_ERR_INVALID_VIDEO_FRAME_SIZE_FOR_H263"); return M4MCS_ERR_INVALID_VIDEO_FRAME_SIZE_FOR_H263; } } /** * Check Video Frame rate correctness */ if( M4VIDEOEDITING_kNullVideo != pParams->OutputVideoFormat ) { switch( pParams->OutputVideoFrameRate ) { case M4VIDEOEDITING_k5_FPS: pC->EncodingVideoFramerate = M4ENCODER_k5_FPS; break; case M4VIDEOEDITING_k7_5_FPS: pC->EncodingVideoFramerate = M4ENCODER_k7_5_FPS; break; case M4VIDEOEDITING_k10_FPS: pC->EncodingVideoFramerate = M4ENCODER_k10_FPS; break; case M4VIDEOEDITING_k12_5_FPS: pC->EncodingVideoFramerate = M4ENCODER_k12_5_FPS; break; case M4VIDEOEDITING_k15_FPS: pC->EncodingVideoFramerate = M4ENCODER_k15_FPS; break; case M4VIDEOEDITING_k20_FPS: pC->EncodingVideoFramerate = M4ENCODER_k20_FPS; break; case M4VIDEOEDITING_k25_FPS: pC->EncodingVideoFramerate = M4ENCODER_k25_FPS; break; case M4VIDEOEDITING_k30_FPS: pC->EncodingVideoFramerate = M4ENCODER_k30_FPS; break; default: M4OSA_TRACE1_1( "M4MCS_setOutputParams: Undefined output video frame rate\ (%d), returning M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_RATE", pParams->OutputVideoFrameRate); return M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_RATE; } } /** * Frame rate check for H263 (only dividers of 30 fps (29.97 actually)) */ if( M4VIDEOEDITING_kH263 == pParams->OutputVideoFormat ) { switch( pC->EncodingVideoFramerate ) { case M4ENCODER_k5_FPS: case M4ENCODER_k7_5_FPS: case M4ENCODER_k10_FPS: case M4ENCODER_k15_FPS: case M4ENCODER_k30_FPS: /* OK */ break; default: M4OSA_TRACE1_0( "M4MCS_setOutputParams():\ returning M4MCS_ERR_INVALID_VIDEO_FRAME_RATE_FOR_H263"); return M4MCS_ERR_INVALID_VIDEO_FRAME_RATE_FOR_H263; } } } /* Set audio parameters */ if( pC->noaudio == M4OSA_FALSE ) { /** * Check Audio Format correctness */ switch( pParams->OutputAudioFormat ) { case M4VIDEOEDITING_kAMR_NB: err = M4MCS_setCurrentAudioEncoder(pContext, pParams->OutputAudioFormat); M4ERR_CHECK_RETURN(err); pC->AudioEncParams.Format = M4ENCODER_kAMRNB; pC->AudioEncParams.Frequency = M4ENCODER_k8000Hz; pC->AudioEncParams.ChannelNum = M4ENCODER_kMono; pC->AudioEncParams.SpecifParam.AmrSID = M4ENCODER_kAmrNoSID; break; case M4VIDEOEDITING_kAAC: err = M4MCS_setCurrentAudioEncoder(pContext, pParams->OutputAudioFormat); M4ERR_CHECK_RETURN(err); pC->AudioEncParams.Format = M4ENCODER_kAAC; pC->AudioEncParams.Frequency = M4ENCODER_k16000Hz; switch( pParams->OutputAudioSamplingFrequency ) { case M4VIDEOEDITING_k8000_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k8000Hz; break; case M4VIDEOEDITING_k16000_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k16000Hz; break; case M4VIDEOEDITING_k22050_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k22050Hz; break; case M4VIDEOEDITING_k24000_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k24000Hz; break; case M4VIDEOEDITING_k32000_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k32000Hz; break; case M4VIDEOEDITING_k44100_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k44100Hz; break; case M4VIDEOEDITING_k48000_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k48000Hz; break; case M4VIDEOEDITING_k11025_ASF: case M4VIDEOEDITING_k12000_ASF: case M4VIDEOEDITING_kDefault_ASF: break; } pC->AudioEncParams.ChannelNum = (pParams->bAudioMono == M4OSA_TRUE) ? \ M4ENCODER_kMono : M4ENCODER_kStereo; pC->AudioEncParams.SpecifParam.AacParam.Regulation = M4ENCODER_kAacRegulNone; //M4ENCODER_kAacBitReservoir /* unused */ pC->AudioEncParams.SpecifParam.AacParam.bIS = M4OSA_FALSE; pC->AudioEncParams.SpecifParam.AacParam.bMS = M4OSA_FALSE; pC->AudioEncParams.SpecifParam.AacParam.bPNS = M4OSA_FALSE; pC->AudioEncParams.SpecifParam.AacParam.bTNS = M4OSA_FALSE; /* TODO change into highspeed asap */ pC->AudioEncParams.SpecifParam.AacParam.bHighSpeed = M4OSA_FALSE; break; /*FlB 26.02.2009: add mp3 as mcs output format, add mp3 encoder*/ case M4VIDEOEDITING_kMP3: err = M4MCS_setCurrentAudioEncoder(pContext, pParams->OutputAudioFormat); M4ERR_CHECK_RETURN(err); pC->AudioEncParams.Format = M4ENCODER_kMP3; pC->AudioEncParams.ChannelNum = (pParams->bAudioMono == M4OSA_TRUE) ? \ M4ENCODER_kMono : M4ENCODER_kStereo; pC->AudioEncParams.Frequency = M4ENCODER_k16000Hz; switch( pParams->OutputAudioSamplingFrequency ) { case M4VIDEOEDITING_k8000_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k8000Hz; break; case M4VIDEOEDITING_k11025_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k11025Hz; break; case M4VIDEOEDITING_k12000_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k12000Hz; break; case M4VIDEOEDITING_k16000_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k16000Hz; break; case M4VIDEOEDITING_k22050_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k22050Hz; break; case M4VIDEOEDITING_k24000_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k24000Hz; break; case M4VIDEOEDITING_k32000_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k32000Hz; break; case M4VIDEOEDITING_k44100_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k44100Hz; break; case M4VIDEOEDITING_k48000_ASF: pC->AudioEncParams.Frequency = M4ENCODER_k48000Hz; break; case M4VIDEOEDITING_kDefault_ASF: break; } break; case M4VIDEOEDITING_kNullAudio: if( pParams->pEffects == M4OSA_NULL || pParams->nbEffects == 0 ) { /* no encoder needed */ pC->AudioEncParams.Format = M4ENCODER_kAudioNULL; pC->AudioEncParams.Frequency = pC->pReaderAudioStream->m_samplingFrequency; pC->AudioEncParams.ChannelNum = (pC->pReaderAudioStream->m_nbChannels == 1) ? \ M4ENCODER_kMono : M4ENCODER_kStereo; } else { pC->AudioEncParams.Frequency = pC->pReaderAudioStream->m_samplingFrequency; pC->AudioEncParams.ChannelNum = (pC->pReaderAudioStream->m_nbChannels == 1) ? \ M4ENCODER_kMono : M4ENCODER_kStereo; switch( pC->InputFileProperties.AudioStreamType ) { case M4VIDEOEDITING_kAMR_NB: M4OSA_TRACE3_0( "M4MCS_setOutputParams calling \ M4MCS_setCurrentAudioEncoder M4VIDEOEDITING_kNull, AMR"); err = M4MCS_setCurrentAudioEncoder(pContext, pC->InputFileProperties.AudioStreamType); M4ERR_CHECK_RETURN(err); pC->AudioEncParams.Format = M4ENCODER_kAMRNB; pC->AudioEncParams.Frequency = M4ENCODER_k8000Hz; pC->AudioEncParams.ChannelNum = M4ENCODER_kMono; if( pC->pReaderAudioStream->m_samplingFrequency != 8000 ) { pC->AudioEncParams.Format = M4ENCODER_kAMRNB; } pC->AudioEncParams.SpecifParam.AmrSID = M4ENCODER_kAmrNoSID; break; case M4VIDEOEDITING_kAAC: M4OSA_TRACE3_0( "M4MCS_setOutputParams calling \ M4MCS_setCurrentAudioEncoder M4VIDEOEDITING_kNull, AAC"); err = M4MCS_setCurrentAudioEncoder(pContext, pC->InputFileProperties.AudioStreamType); M4ERR_CHECK_RETURN(err); pC->AudioEncParams.Format = M4ENCODER_kAAC; pC->AudioEncParams.SpecifParam.AacParam.Regulation = M4ENCODER_kAacRegulNone; //M4ENCODER_kAacBitReservoir pC->AudioEncParams.Frequency = M4ENCODER_k16000Hz; pC->AudioEncParams.Frequency = M4ENCODER_k16000Hz; switch( pC->pReaderAudioStream-> m_samplingFrequency ) { case 16000: pC->AudioEncParams.Frequency = M4ENCODER_k16000Hz; break; case 22050: pC->AudioEncParams.Frequency = M4ENCODER_k22050Hz; break; case 24000: pC->AudioEncParams.Frequency = M4ENCODER_k24000Hz; break; case 32000: pC->AudioEncParams.Frequency = M4ENCODER_k32000Hz; break; case 44100: pC->AudioEncParams.Frequency = M4ENCODER_k44100Hz; break; case 48000: pC->AudioEncParams.Frequency = M4ENCODER_k48000Hz; break; default: pC->AudioEncParams.Format = M4ENCODER_kAAC; break; } /* unused */ pC->AudioEncParams.SpecifParam.AacParam.bIS = M4OSA_FALSE; pC->AudioEncParams.SpecifParam.AacParam.bMS = M4OSA_FALSE; pC->AudioEncParams.SpecifParam.AacParam.bPNS = M4OSA_FALSE; pC->AudioEncParams.SpecifParam.AacParam.bTNS = M4OSA_FALSE; /* TODO change into highspeed asap */ pC->AudioEncParams.SpecifParam.AacParam.bHighSpeed = M4OSA_FALSE; break; case M4VIDEOEDITING_kMP3: M4OSA_TRACE3_0( "M4MCS_setOutputParams calling\ M4MCS_setCurrentAudioEncoder M4VIDEOEDITING_kNull, MP3"); err = M4MCS_setCurrentAudioEncoder(pContext, pC->InputFileProperties.AudioStreamType); M4ERR_CHECK_RETURN(err); pC->AudioEncParams.Format = M4ENCODER_kMP3; pC->AudioEncParams.Frequency = M4ENCODER_k16000Hz; switch( pC->pReaderAudioStream-> m_samplingFrequency ) { case 8000: pC->AudioEncParams.Frequency = M4ENCODER_k8000Hz; break; case 16000: pC->AudioEncParams.Frequency = M4ENCODER_k16000Hz; break; case 22050: pC->AudioEncParams.Frequency = M4ENCODER_k22050Hz; break; case 24000: pC->AudioEncParams.Frequency = M4ENCODER_k24000Hz; break; case 32000: pC->AudioEncParams.Frequency = M4ENCODER_k32000Hz; break; case 44100: pC->AudioEncParams.Frequency = M4ENCODER_k44100Hz; break; case 48000: pC->AudioEncParams.Frequency = M4ENCODER_k48000Hz; break; default: pC->AudioEncParams.Format = M4ENCODER_kMP3; break; } break; case M4VIDEOEDITING_kEVRC: case M4VIDEOEDITING_kUnsupportedAudio: default: M4OSA_TRACE1_1( "M4MCS_setOutputParams: Output audio format (%d) is\ incompatible with audio effects, returning \ M4MCS_ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT", pC->InputFileProperties.AudioStreamType); return M4MCS_ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT; } } break; /* EVRC // case M4VIDEOEDITING_kEVRC: // // err = M4MCS_setCurrentAudioEncoder(pContext, pParams->\ // OutputAudioFormat); // M4ERR_CHECK_RETURN(err); // // pC->AudioEncParams.Format = M4ENCODER_kEVRC; // pC->AudioEncParams.Frequency = M4ENCODER_k8000Hz; // pC->AudioEncParams.ChannelNum = M4ENCODER_kMono; // break; */ default: M4OSA_TRACE1_1("M4MCS_setOutputParams: Undefined output audio format (%d),\ returning M4MCS_ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT", pParams->OutputAudioFormat); return M4MCS_ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT; } } if( pParams->pOutputPCMfile != M4OSA_NULL ) { pC->pOutputPCMfile = pParams->pOutputPCMfile; /* Open output PCM file */ pC->pOsaFileWritPtr->openWrite(&(pC->pOutputPCMfile), pParams->pOutputPCMfile, M4OSA_kFileWrite); } else { pC->pOutputPCMfile = M4OSA_NULL; } /*Store media rendering parameter into the internal context*/ pC->MediaRendering = pParams->MediaRendering; /* Add audio effects*/ /*Copy MCS effects structure into internal context*/ if( pParams->nbEffects > 0 ) { M4OSA_UInt32 j = 0; pC->nbEffects = pParams->nbEffects; pC->pEffects = (M4MCS_EffectSettings *)M4OSA_32bitAlignedMalloc(pC->nbEffects \ *sizeof(M4MCS_EffectSettings), M4MCS, (M4OSA_Char *)"Allocation of effects list"); if( pC->pEffects == M4OSA_NULL ) { M4OSA_TRACE1_0("M4MCS_setOutputParams(): allocation error"); return M4ERR_ALLOC; } for ( j = 0; j < pC->nbEffects; j++ ) { /* Copy effect to "local" structure */ memcpy((void *) &(pC->pEffects[j]), (void *) &(pParams->pEffects[j]), sizeof(M4MCS_EffectSettings)); switch( pC->pEffects[j].AudioEffectType ) { case M4MCS_kAudioEffectType_None: M4OSA_TRACE3_1( "M4MCS_setOutputParams(): effect type %i is None", j); pC->pEffects[j].pExtAudioEffectFctCtxt = M4OSA_NULL; pC->pEffects[j].ExtAudioEffectFct = M4OSA_NULL; break; case M4MCS_kAudioEffectType_FadeIn: M4OSA_TRACE3_1( "M4MCS_setOutputParams(): effect type %i is FadeIn", j); pC->pEffects[j].pExtAudioEffectFctCtxt = M4OSA_NULL; pC->pEffects[j].ExtAudioEffectFct = M4MCS_editAudioEffectFct_FadeIn; break; case M4MCS_kAudioEffectType_FadeOut: M4OSA_TRACE3_1( "M4MCS_setOutputParams(): effect type %i is FadeOut", j); pC->pEffects[j].pExtAudioEffectFctCtxt = M4OSA_NULL; pC->pEffects[j].ExtAudioEffectFct = M4MCS_editAudioEffectFct_FadeOut; break; case M4MCS_kAudioEffectType_External: M4OSA_TRACE3_1( "M4MCS_setOutputParams(): effect type %i is External", j); if( pParams->pEffects != M4OSA_NULL ) { if( pParams->pEffects[j].ExtAudioEffectFct == M4OSA_NULL ) { M4OSA_TRACE1_1("M4MCS_setOutputParams(): no external effect function\ associated to external effect number %i", j); return M4ERR_PARAMETER; } pC->pEffects[j].pExtAudioEffectFctCtxt = pParams->pEffects[j].pExtAudioEffectFctCtxt; pC->pEffects[j].ExtAudioEffectFct = pParams->pEffects[j].ExtAudioEffectFct; } break; default: M4OSA_TRACE1_0( "M4MCS_setOutputParams(): effect type not recognized"); return M4ERR_PARAMETER; } } } else { pC->nbEffects = 0; pC->pEffects = M4OSA_NULL; } /** * Update state automaton */ pC->State = M4MCS_kState_SET; /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_setOutputParams(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_setEncodingParams(M4MCS_Context pContext, M4MCS_EncodingParams* pRates) * @brief Set the values of the encoding parameters * @note Must be called before M4MCS_checkParamsAndStart(). * @param pContext (IN) MCS context * @param pRates (IN) Transcoding parameters * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL (debug only) * @return M4ERR_STATE: MCS is not in an appropriate state for this function to be called * @return M4MCS_ERR_AUDIOBITRATE_TOO_HIGH: Audio bitrate too high (we limit to 96 kbps) * @return M4MCS_ERR_AUDIOBITRATE_TOO_LOW: Audio bitrate is too low (16 kbps min for aac, 12.2 * for amr, 8 for mp3) * @return M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT: Begin cut and End cut are equals * @return M4MCS_ERR_BEGIN_CUT_LARGER_THAN_DURATION: Begin cut time is larger than the input clip * duration * @return M4MCS_ERR_END_CUT_SMALLER_THAN_BEGIN_CUT: End cut time is smaller than begin cut time * @return M4MCS_ERR_MAXFILESIZE_TOO_SMALL: Not enough space to store whole output file at given * bitrates * @return M4MCS_ERR_VIDEOBITRATE_TOO_HIGH: Video bitrate too high (we limit to 800 kbps) * @return M4MCS_ERR_VIDEOBITRATE_TOO_LOW: Video bitrate too low ****************************************************************************** */ M4OSA_ERR M4MCS_setEncodingParams( M4MCS_Context pContext, M4MCS_EncodingParams *pRates ) { M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); M4OSA_UInt32 j = 0; M4OSA_TRACE2_2( "M4MCS_setEncodingParams called with pContext=0x%x, pRates=0x%x", pContext, pRates); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4MCS_setEncodingParams: pContext is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pRates), M4ERR_PARAMETER, "M4MCS_setEncodingParams: pRates is M4OSA_NULL"); #ifdef M4MCS_SUPPORT_STILL_PICTURE if( pC->m_bIsStillPicture ) { /** * Call the corresponding still picture MCS function*/ return M4MCS_stillPicSetEncodingParams(pC, pRates); } #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ /** * Check state automaton */ if( M4MCS_kState_SET != pC->State ) { M4OSA_TRACE1_1( "M4MCS_setEncodingParams(): Wrong State (%d), returning M4ERR_STATE", pC->State); return M4ERR_STATE; } /* Set given values */ pC->uiVideoBitrate = pRates->OutputVideoBitrate; pC->uiAudioBitrate = pRates->OutputAudioBitrate; pC->uiBeginCutTime = pRates->BeginCutTime; pC->uiEndCutTime = pRates->EndCutTime; pC->uiMaxFileSize = pRates->OutputFileSize; /** * Check begin cut time validity */ if( pC->uiBeginCutTime >= pC->InputFileProperties.uiClipDuration ) { M4OSA_TRACE1_2("M4MCS_setEncodingParams(): Begin cut larger than duration (%d>%d),\ returning M4MCS_ERR_BEGIN_CUT_LARGER_THAN_DURATION", pC->uiBeginCutTime, pC->InputFileProperties.uiClipDuration); return M4MCS_ERR_BEGIN_CUT_LARGER_THAN_DURATION; } /** * If end cut time is too large, we set it to the clip duration */ if( pC->uiEndCutTime > pC->InputFileProperties.uiClipDuration ) { pC->uiEndCutTime = pC->InputFileProperties.uiClipDuration; } /** * Check end cut time validity */ if( pC->uiEndCutTime > 0 ) { if( pC->uiEndCutTime < pC->uiBeginCutTime ) { M4OSA_TRACE1_2("M4MCS_setEncodingParams(): Begin cut greater than end cut (%d,%d), \ returning M4MCS_ERR_END_CUT_SMALLER_THAN_BEGIN_CUT", pC->uiBeginCutTime, pC->uiEndCutTime); return M4MCS_ERR_END_CUT_SMALLER_THAN_BEGIN_CUT; } if( pC->uiEndCutTime == pC->uiBeginCutTime ) { M4OSA_TRACE1_2("M4MCS_setEncodingParams(): Begin and End cuts are equal (%d,%d),\ returning M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT", pC->uiBeginCutTime, pC->uiEndCutTime); return M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT; } } /** * FlB 2009.03.04: check audio effects start time and duration validity*/ for ( j = 0; j < pC->nbEffects; j++ ) { M4OSA_UInt32 outputEndCut = pC->uiEndCutTime; if( pC->uiEndCutTime == 0 ) { outputEndCut = pC->InputFileProperties.uiClipDuration; } if( pC->pEffects[j].uiStartTime > (outputEndCut - pC->uiBeginCutTime) ) { M4OSA_TRACE1_2("M4MCS_setEncodingParams(): Effects start time is larger than\ duration (%d,%d), returning M4ERR_PARAMETER", pC->pEffects[j].uiStartTime, (pC->uiEndCutTime - pC->uiBeginCutTime)); return M4ERR_PARAMETER; } if( pC->pEffects[j].uiStartTime + pC->pEffects[j].uiDuration > \ (outputEndCut - pC->uiBeginCutTime) ) { /* Re-adjust the effect duration until the end of the output clip*/ pC->pEffects[j].uiDuration = (outputEndCut - pC->uiBeginCutTime) - \ pC->pEffects[j].uiStartTime; } } /* Check audio bitrate consistency */ if( ( pC->noaudio == M4OSA_FALSE) && (pC->AudioEncParams.Format != M4ENCODER_kAudioNULL) ) { if( pC->uiAudioBitrate != M4VIDEOEDITING_kUndefinedBitrate ) { if( pC->AudioEncParams.Format == M4ENCODER_kAMRNB ) { if( pC->uiAudioBitrate > M4VIDEOEDITING_k12_2_KBPS ) return M4MCS_ERR_AUDIOBITRATE_TOO_HIGH; if( pC->uiAudioBitrate < M4VIDEOEDITING_k12_2_KBPS ) return M4MCS_ERR_AUDIOBITRATE_TOO_LOW; } //EVRC // else if(pC->AudioEncParams.Format == M4ENCODER_kEVRC) // { // if(pC->uiAudioBitrate > M4VIDEOEDITING_k9_2_KBPS) // return M4MCS_ERR_AUDIOBITRATE_TOO_HIGH; // if(pC->uiAudioBitrate < M4VIDEOEDITING_k9_2_KBPS) // return M4MCS_ERR_AUDIOBITRATE_TOO_LOW; // } /*FlB 26.02.2009: add mp3 as mcs output format, add mp3 encoder*/ else if( pC->AudioEncParams.Format == M4ENCODER_kMP3 ) { if( pC->AudioEncParams.Frequency >= M4ENCODER_k32000Hz ) { /*Mpeg layer 1*/ if( pC->uiAudioBitrate > 320000 ) return M4MCS_ERR_AUDIOBITRATE_TOO_HIGH; if( pC->uiAudioBitrate < 32000 ) return M4MCS_ERR_AUDIOBITRATE_TOO_LOW; } else if( pC->AudioEncParams.Frequency >= M4ENCODER_k16000Hz ) { /*Mpeg layer 2*/ if( pC->uiAudioBitrate > 160000 ) return M4MCS_ERR_AUDIOBITRATE_TOO_HIGH; if( ( pC->uiAudioBitrate < 8000 && pC->AudioEncParams.ChannelNum == M4ENCODER_kMono) || (pC->uiAudioBitrate < 16000 && pC->AudioEncParams.ChannelNum == M4ENCODER_kStereo) ) return M4MCS_ERR_AUDIOBITRATE_TOO_LOW; } else if( pC->AudioEncParams.Frequency == M4ENCODER_k8000Hz || pC->AudioEncParams.Frequency == M4ENCODER_k11025Hz || pC->AudioEncParams.Frequency == M4ENCODER_k12000Hz ) { /*Mpeg layer 2.5*/ if( pC->uiAudioBitrate > 64000 ) return M4MCS_ERR_AUDIOBITRATE_TOO_HIGH; if( ( pC->uiAudioBitrate < 8000 && pC->AudioEncParams.ChannelNum == M4ENCODER_kMono) || (pC->uiAudioBitrate < 16000 && pC->AudioEncParams.ChannelNum == M4ENCODER_kStereo) ) return M4MCS_ERR_AUDIOBITRATE_TOO_LOW; } else { M4OSA_TRACE1_1("M4MCS_setEncodingParams: MP3 audio sampling frequency error\ (%d)", pC->AudioEncParams.Frequency); return M4ERR_PARAMETER; } } else { if( pC->uiAudioBitrate > M4VIDEOEDITING_k192_KBPS ) return M4MCS_ERR_AUDIOBITRATE_TOO_HIGH; if( pC->AudioEncParams.ChannelNum == M4ENCODER_kMono ) { if( pC->uiAudioBitrate < M4VIDEOEDITING_k16_KBPS ) return M4MCS_ERR_AUDIOBITRATE_TOO_LOW; } else { if( pC->uiAudioBitrate < M4VIDEOEDITING_k32_KBPS ) return M4MCS_ERR_AUDIOBITRATE_TOO_LOW; } } } } else { /* NULL audio : copy input file bitrate */ pC->uiAudioBitrate = pC->InputFileProperties.uiAudioBitrate; } /* Check video bitrate consistency */ if( ( pC->novideo == M4OSA_FALSE) && (pC->EncodingVideoFormat != M4ENCODER_kNULL) ) { if( pC->uiVideoBitrate != M4VIDEOEDITING_kUndefinedBitrate ) { if( pC->uiVideoBitrate > M4VIDEOEDITING_k8_MBPS ) return M4MCS_ERR_VIDEOBITRATE_TOO_HIGH; if( pC->uiVideoBitrate < M4VIDEOEDITING_k16_KBPS ) return M4MCS_ERR_VIDEOBITRATE_TOO_LOW; } } else { /* NULL video : copy input file bitrate */ pC->uiVideoBitrate = pC->InputFileProperties.uiVideoBitrate; } if( pRates->OutputVideoTimescale <= 30000 && pRates->OutputVideoTimescale > 0 ) { pC->outputVideoTimescale = pRates->OutputVideoTimescale; } /* Check file size */ return M4MCS_intCheckMaxFileSize(pC); } /** ****************************************************************************** * M4OSA_ERR M4MCS_getExtendedEncodingParams(M4MCS_Context pContext, M4MCS_EncodingParams* pRates) * @brief Get the extended values of the encoding parameters * @note Could be called after M4MCS_setEncodingParams. * @param pContext (IN) MCS context * @param pRates (OUT) Transcoding parameters * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL (debug only) * @return M4ERR_STATE: MCS is not in an appropriate state for this function to be called * @return M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT: Encoding settings would produce a null duration * clip = encoding is impossible ****************************************************************************** */ M4OSA_ERR M4MCS_getExtendedEncodingParams( M4MCS_Context pContext, M4MCS_EncodingParams *pRates ) { M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); M4OSA_Int32 minaudiobitrate; M4OSA_Int32 minvideobitrate; M4OSA_Int32 maxcombinedbitrate; M4OSA_Int32 calcbitrate; M4OSA_UInt32 maxduration; M4OSA_UInt32 calcduration; M4OSA_Bool fixed_audio = M4OSA_FALSE; M4OSA_Bool fixed_video = M4OSA_FALSE; #ifdef M4MCS_SUPPORT_STILL_PICTURE if( pC->m_bIsStillPicture ) { /** * Call the corresponding still picture MCS function*/ return M4MCS_stillPicGetExtendedEncodingParams(pC, pRates); } #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ pRates->OutputVideoBitrate = M4MCS_intGetNearestBitrate(pC->uiVideoBitrate, 0); pRates->OutputAudioBitrate = M4MCS_intGetNearestBitrate(pC->uiAudioBitrate, 0); pRates->BeginCutTime = pC->uiBeginCutTime; pRates->EndCutTime = pC->uiEndCutTime; pRates->OutputFileSize = pC->uiMaxFileSize; /** * Check state automaton */ if( M4MCS_kState_SET != pC->State ) { M4OSA_TRACE1_1("M4MCS_getExtendedEncodingParams(): Wrong State (%d),\ returning M4ERR_STATE", pC->State); return M4ERR_STATE; } /* Compute min audio bitrate */ if( pC->noaudio ) { fixed_audio = M4OSA_TRUE; pRates->OutputAudioBitrate = 0; minaudiobitrate = 0; } else if( pC->AudioEncParams.Format == M4ENCODER_kAudioNULL ) { fixed_audio = M4OSA_TRUE; pRates->OutputAudioBitrate = pC->InputFileProperties.uiAudioBitrate; minaudiobitrate = pC->InputFileProperties.uiAudioBitrate; } else { if( pC->AudioEncParams.Format == M4ENCODER_kAMRNB ) { fixed_audio = M4OSA_TRUE; pRates->OutputAudioBitrate = M4VIDEOEDITING_k12_2_KBPS; minaudiobitrate = M4VIDEOEDITING_k12_2_KBPS; } //EVRC // if(pC->AudioEncParams.Format == M4ENCODER_kEVRC) // { // fixed_audio = M4OSA_TRUE; // pRates->OutputAudioBitrate = M4VIDEOEDITING_k9_2_KBPS; // minaudiobitrate = M4VIDEOEDITING_k9_2_KBPS; // } /*FlB 26.02.2009: add mp3 as mcs output format*/ else if( pC->AudioEncParams.Format == M4ENCODER_kMP3 ) { minaudiobitrate = M4VIDEOEDITING_k32_KBPS; /*Default min audio bitrate for MPEG layer 1, for both mono and stereo channels*/ } else { minaudiobitrate = (pC->AudioEncParams.ChannelNum == M4ENCODER_kMono) ? M4VIDEOEDITING_k16_KBPS : M4VIDEOEDITING_k32_KBPS; } } /* Check audio bitrate is in the correct range */ if( fixed_audio == M4OSA_FALSE ) { if( ( pC->uiAudioBitrate > 0) && (pRates->OutputAudioBitrate < minaudiobitrate) ) { pRates->OutputAudioBitrate = minaudiobitrate; } if( pRates->OutputAudioBitrate > M4VIDEOEDITING_k96_KBPS ) { pRates->OutputAudioBitrate = M4VIDEOEDITING_k96_KBPS; } } /* Compute min video bitrate */ if( pC->novideo ) { fixed_video = M4OSA_TRUE; pRates->OutputVideoBitrate = 0; minvideobitrate = 0; } else if( pC->EncodingVideoFormat == M4ENCODER_kNULL ) { fixed_video = M4OSA_TRUE; pRates->OutputVideoBitrate = pC->InputFileProperties.uiVideoBitrate; minvideobitrate = pC->InputFileProperties.uiVideoBitrate; } else { minvideobitrate = M4VIDEOEDITING_k16_KBPS; } /* Check video bitrate is in the correct range */ if( fixed_video == M4OSA_FALSE ) { if( ( pC->uiVideoBitrate > 0) && (pRates->OutputVideoBitrate < minvideobitrate) ) { pRates->OutputVideoBitrate = minvideobitrate; } /*+ New Encoder bitrates */ if( pRates->OutputVideoBitrate > M4VIDEOEDITING_k8_MBPS ) { pRates->OutputVideoBitrate = M4VIDEOEDITING_k8_MBPS; } /*- New Encoder bitrates */ } /* Check cut times are in correct range */ if( ( pRates->BeginCutTime >= pC->InputFileProperties.uiClipDuration) || (( pRates->BeginCutTime >= pRates->EndCutTime) && (pRates->EndCutTime > 0)) ) { pRates->BeginCutTime = 0; pRates->EndCutTime = 0; } if( pRates->EndCutTime == 0 ) calcduration = pC->InputFileProperties.uiClipDuration - pRates->BeginCutTime; else calcduration = pRates->EndCutTime - pRates->BeginCutTime; /* priority 1 : max file size */ if( pRates->OutputFileSize == 0 ) { /* we can put maximum values for all undefined parameters */ if( pRates->EndCutTime == 0 ) { pRates->EndCutTime = pC->InputFileProperties.uiClipDuration; } if( ( pRates->OutputAudioBitrate == M4VIDEOEDITING_kUndefinedBitrate) && (fixed_audio == M4OSA_FALSE) ) { pRates->OutputAudioBitrate = M4VIDEOEDITING_k96_KBPS; } if( ( pRates->OutputVideoBitrate == M4VIDEOEDITING_kUndefinedBitrate) && (fixed_video == M4OSA_FALSE) ) { /*+ New Encoder bitrates */ pRates->OutputVideoBitrate = M4VIDEOEDITING_k8_MBPS; /*- New Encoder bitrates */ } } else { /* compute max duration */ maxduration = (M4OSA_UInt32)(pRates->OutputFileSize / M4MCS_MOOV_OVER_FILESIZE_RATIO / (minvideobitrate + minaudiobitrate) * 8000.0); if( maxduration + pRates->BeginCutTime > pC->InputFileProperties.uiClipDuration ) { maxduration = pC->InputFileProperties.uiClipDuration - pRates->BeginCutTime; } /* priority 2 : cut times */ if( ( pRates->BeginCutTime > 0) || (pRates->EndCutTime > 0) ) { if( calcduration > maxduration ) { calcduration = maxduration; } if( calcduration == 0 ) { return M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT; } maxcombinedbitrate = (M4OSA_UInt32)(pRates->OutputFileSize / M4MCS_MOOV_OVER_FILESIZE_RATIO / (calcduration / 8000.0)); /* audio and video bitrates */ if( ( pRates->OutputAudioBitrate == M4VIDEOEDITING_kUndefinedBitrate) && (pRates->OutputVideoBitrate == M4VIDEOEDITING_kUndefinedBitrate) ) { /* set audio = 1/3 and video = 2/3 */ if( fixed_audio == M4OSA_FALSE ) { if( pC->novideo ) pRates->OutputAudioBitrate = M4MCS_intGetNearestBitrate(maxcombinedbitrate, 0); else pRates->OutputAudioBitrate = M4MCS_intGetNearestBitrate(maxcombinedbitrate / 3, 0); if( pRates->OutputAudioBitrate < minaudiobitrate ) pRates->OutputAudioBitrate = minaudiobitrate; if( pRates->OutputAudioBitrate > M4VIDEOEDITING_k96_KBPS ) pRates->OutputAudioBitrate = M4VIDEOEDITING_k96_KBPS; } if( fixed_video == M4OSA_FALSE ) { pRates->OutputVideoBitrate = M4MCS_intGetNearestBitrate(maxcombinedbitrate - pRates->OutputAudioBitrate, 0); if( pRates->OutputVideoBitrate < minvideobitrate ) pRates->OutputVideoBitrate = minvideobitrate; if( pRates->OutputVideoBitrate > M4VIDEOEDITING_k8_MBPS ) pRates->OutputVideoBitrate = M4VIDEOEDITING_k8_MBPS; /*+ New Encoder bitrates */ } } else { /* priority 3 : audio bitrate */ if( pRates->OutputAudioBitrate != M4VIDEOEDITING_kUndefinedBitrate ) { while( ( fixed_audio == M4OSA_FALSE) && (pRates->OutputAudioBitrate >= minaudiobitrate) && (pRates->OutputAudioBitrate + minvideobitrate > maxcombinedbitrate) ) { pRates->OutputAudioBitrate = M4MCS_intGetNearestBitrate( pRates->OutputAudioBitrate, -1); } if( ( fixed_audio == M4OSA_FALSE) && (pRates->OutputAudioBitrate < minaudiobitrate) ) { pRates->OutputAudioBitrate = minaudiobitrate; } calcbitrate = M4MCS_intGetNearestBitrate( maxcombinedbitrate - pRates->OutputAudioBitrate, 0); if( calcbitrate < minvideobitrate ) calcbitrate = minvideobitrate; if( calcbitrate > M4VIDEOEDITING_k8_MBPS ) calcbitrate = M4VIDEOEDITING_k8_MBPS; if( ( fixed_video == M4OSA_FALSE) && (( pRates->OutputVideoBitrate == M4VIDEOEDITING_kUndefinedBitrate) || (pRates->OutputVideoBitrate > calcbitrate)) ) { pRates->OutputVideoBitrate = calcbitrate; } } else { /* priority 4 : video bitrate */ if( pRates->OutputVideoBitrate != M4VIDEOEDITING_kUndefinedBitrate ) { while( ( fixed_video == M4OSA_FALSE) && (pRates->OutputVideoBitrate >= minvideobitrate) && (pRates->OutputVideoBitrate + minaudiobitrate > maxcombinedbitrate) ) { pRates->OutputVideoBitrate = M4MCS_intGetNearestBitrate( pRates->OutputVideoBitrate, -1); } if( ( fixed_video == M4OSA_FALSE) && (pRates->OutputVideoBitrate < minvideobitrate) ) { pRates->OutputVideoBitrate = minvideobitrate; } calcbitrate = M4MCS_intGetNearestBitrate(maxcombinedbitrate - pRates->OutputVideoBitrate, 0); if( calcbitrate < minaudiobitrate ) calcbitrate = minaudiobitrate; if( calcbitrate > M4VIDEOEDITING_k96_KBPS ) calcbitrate = M4VIDEOEDITING_k96_KBPS; if( ( fixed_audio == M4OSA_FALSE) && (( pRates->OutputAudioBitrate == M4VIDEOEDITING_kUndefinedBitrate) || (pRates->OutputAudioBitrate > calcbitrate)) ) { pRates->OutputAudioBitrate = calcbitrate; } } } } } else { /* priority 3 : audio bitrate */ if( pRates->OutputAudioBitrate != M4VIDEOEDITING_kUndefinedBitrate ) { /* priority 4 : video bitrate */ if( pRates->OutputVideoBitrate != M4VIDEOEDITING_kUndefinedBitrate ) { /* compute max duration */ maxduration = (M4OSA_UInt32)(pRates->OutputFileSize / M4MCS_MOOV_OVER_FILESIZE_RATIO / (pRates->OutputVideoBitrate + pRates->OutputAudioBitrate) * 8000.0); if( maxduration + pRates->BeginCutTime > pC->InputFileProperties.uiClipDuration ) { maxduration = pC->InputFileProperties.uiClipDuration - pRates->BeginCutTime; } if( calcduration > maxduration ) { calcduration = maxduration; } if( calcduration == 0 ) { return M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT; } } else { /* start with min video bitrate */ pRates->OutputVideoBitrate = minvideobitrate; /* compute max duration */ maxduration = (M4OSA_UInt32)(pRates->OutputFileSize / M4MCS_MOOV_OVER_FILESIZE_RATIO / (pRates->OutputVideoBitrate + pRates->OutputAudioBitrate) * 8000.0); if( maxduration + pRates->BeginCutTime > pC->InputFileProperties.uiClipDuration ) { maxduration = pC->InputFileProperties.uiClipDuration - pRates->BeginCutTime; } if( calcduration > maxduration ) { calcduration = maxduration; } if( calcduration == 0 ) { return M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT; } /* search max possible video bitrate */ maxcombinedbitrate = (M4OSA_UInt32)(pRates->OutputFileSize / M4MCS_MOOV_OVER_FILESIZE_RATIO / (calcduration / 8000.0)); while( ( fixed_video == M4OSA_FALSE) && (pRates->OutputVideoBitrate < M4VIDEOEDITING_k8_MBPS) ) /*+ New Encoder bitrates */ { calcbitrate = M4MCS_intGetNearestBitrate( pRates->OutputVideoBitrate, +1); if( calcbitrate + pRates->OutputAudioBitrate <= maxcombinedbitrate ) pRates->OutputVideoBitrate = calcbitrate; else break; } } } else { /* priority 4 : video bitrate */ if( pRates->OutputVideoBitrate != M4VIDEOEDITING_kUndefinedBitrate ) { /* start with min audio bitrate */ pRates->OutputAudioBitrate = minaudiobitrate; /* compute max duration */ maxduration = (M4OSA_UInt32)(pRates->OutputFileSize / M4MCS_MOOV_OVER_FILESIZE_RATIO / (pRates->OutputVideoBitrate + pRates->OutputAudioBitrate) * 8000.0); if( maxduration + pRates->BeginCutTime > pC->InputFileProperties.uiClipDuration ) { maxduration = pC->InputFileProperties.uiClipDuration - pRates->BeginCutTime; } if( calcduration > maxduration ) { calcduration = maxduration; } if( calcduration == 0 ) { return M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT; } /* search max possible audio bitrate */ maxcombinedbitrate = (M4OSA_UInt32)(pRates->OutputFileSize / M4MCS_MOOV_OVER_FILESIZE_RATIO / (calcduration / 8000.0)); while( ( fixed_audio == M4OSA_FALSE) && (pRates->OutputAudioBitrate < M4VIDEOEDITING_k96_KBPS) ) { calcbitrate = M4MCS_intGetNearestBitrate( pRates->OutputAudioBitrate, +1); if( calcbitrate + pRates->OutputVideoBitrate <= maxcombinedbitrate ) pRates->OutputAudioBitrate = calcbitrate; else break; } } else { /* compute max duration */ maxduration = (M4OSA_UInt32)(pRates->OutputFileSize / M4MCS_MOOV_OVER_FILESIZE_RATIO / (minvideobitrate + minaudiobitrate) * 8000.0); if( maxduration + pRates->BeginCutTime > pC->InputFileProperties.uiClipDuration ) { maxduration = pC->InputFileProperties.uiClipDuration - pRates->BeginCutTime; } if( calcduration > maxduration ) { calcduration = maxduration; } if( calcduration == 0 ) { return M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT; } /* set audio = 1/3 and video = 2/3 */ maxcombinedbitrate = (M4OSA_UInt32)(pRates->OutputFileSize / M4MCS_MOOV_OVER_FILESIZE_RATIO / (calcduration / 8000.0)); if( fixed_audio == M4OSA_FALSE ) { if( pC->novideo ) pRates->OutputAudioBitrate = M4MCS_intGetNearestBitrate(maxcombinedbitrate, 0); else pRates->OutputAudioBitrate = M4MCS_intGetNearestBitrate(maxcombinedbitrate / 3, 0); if( pRates->OutputAudioBitrate < minaudiobitrate ) pRates->OutputAudioBitrate = minaudiobitrate; if( pRates->OutputAudioBitrate > M4VIDEOEDITING_k96_KBPS ) pRates->OutputAudioBitrate = M4VIDEOEDITING_k96_KBPS; } if( fixed_video == M4OSA_FALSE ) { pRates->OutputVideoBitrate = M4MCS_intGetNearestBitrate(maxcombinedbitrate - pRates->OutputAudioBitrate, 0); if( pRates->OutputVideoBitrate < minvideobitrate ) pRates->OutputVideoBitrate = minvideobitrate; if( pRates->OutputVideoBitrate > M4VIDEOEDITING_k8_MBPS ) pRates->OutputVideoBitrate = M4VIDEOEDITING_k8_MBPS; /*+ New Encoder bitrates */ } } } } } /* recompute max duration with final bitrates */ if( pRates->OutputFileSize > 0 ) { maxduration = (M4OSA_UInt32)(pRates->OutputFileSize / M4MCS_MOOV_OVER_FILESIZE_RATIO / (pRates->OutputVideoBitrate + pRates->OutputAudioBitrate) * 8000.0); } else { maxduration = pC->InputFileProperties.uiClipDuration; } if( maxduration + pRates->BeginCutTime > pC->InputFileProperties.uiClipDuration ) { maxduration = pC->InputFileProperties.uiClipDuration - pRates->BeginCutTime; } if( pRates->EndCutTime == 0 ) { pRates->EndCutTime = pRates->BeginCutTime + maxduration; } else { calcduration = pRates->EndCutTime - pRates->BeginCutTime; if( calcduration > maxduration ) { pRates->EndCutTime = pRates->BeginCutTime + maxduration; } } /* Should never happen : constraints are too strong */ if( pRates->EndCutTime == pRates->BeginCutTime ) { return M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT; } /* estimated resulting file size */ pRates->OutputFileSize = (M4OSA_UInt32)(M4MCS_MOOV_OVER_FILESIZE_RATIO * (pRates->OutputVideoBitrate + pRates->OutputAudioBitrate) * (( pRates->EndCutTime - pRates->BeginCutTime) / 8000.0)); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_checkParamsAndStart(M4MCS_Context pContext) * @brief Check parameters to start * @note * @param pContext (IN) MCS context * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL (debug only) * @return M4ERR_STATE: MCS is not in an appropriate state for * this function to be called * @return M4MCS_ERR_AUDIOBITRATE_TOO_HIGH: * Audio bitrate too high (we limit to 96 kbps) * @return M4MCS_ERR_AUDIOBITRATE_TOO_LOW: * Audio bitrate is too low (16 kbps min for aac, * 12.2 for amr, 8 for mp3) * @return M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT: * Begin cut and End cut are equals * @return M4MCS_ERR_BEGIN_CUT_LARGER_THAN_DURATION: * Begin cut time is larger than the input * clip duration * @return M4MCS_ERR_END_CUT_SMALLER_THAN_BEGIN_CUT: * End cut time is smaller than begin cut time * @return M4MCS_ERR_MAXFILESIZE_TOO_SMALL: * Not enough space to store whole output * file at given bitrates * @return M4MCS_ERR_VIDEOBITRATE_TOO_HIGH: * Video bitrate too high (we limit to 800 kbps) * @return M4MCS_ERR_VIDEOBITRATE_TOO_LOW: * Video bitrate too low ****************************************************************************** */ M4OSA_ERR M4MCS_checkParamsAndStart( M4MCS_Context pContext ) { M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); M4MCS_EncodingParams VerifyRates; M4OSA_ERR err; /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4MCS_checkParamsAndStart: pContext is M4OSA_NULL"); #ifdef M4MCS_SUPPORT_STILL_PICTURE if( pC->m_bIsStillPicture ) { /** * Call the corresponding still picture MCS function*/ return M4MCS_stillPicCheckParamsAndStart(pC); } #endif /*M4MCS_SUPPORT_STILL_PICTURE*/ /** * Check state automaton */ if( M4MCS_kState_SET != pC->State ) { M4OSA_TRACE1_1( "M4MCS_checkParamsAndStart(): Wrong State (%d), returning M4ERR_STATE", pC->State); return M4ERR_STATE; } /* Audio bitrate should not stay undefined at this point */ if( ( pC->noaudio == M4OSA_FALSE) && (pC->AudioEncParams.Format != M4ENCODER_kAudioNULL) && (pC->uiAudioBitrate == M4VIDEOEDITING_kUndefinedBitrate) ) { M4OSA_TRACE1_0("M4MCS_checkParamsAndStart : undefined audio bitrate"); return M4MCS_ERR_AUDIOBITRATE_TOO_LOW; } /* Video bitrate should not stay undefined at this point */ if( ( pC->novideo == M4OSA_FALSE) && (pC->EncodingVideoFormat != M4ENCODER_kNULL) && (pC->uiVideoBitrate == M4VIDEOEDITING_kUndefinedBitrate) ) { M4OSA_TRACE1_0("M4MCS_checkParamsAndStart : undefined video bitrate"); return M4MCS_ERR_VIDEOBITRATE_TOO_LOW; } /* Set end cut time if necessary (not an error) */ if( pC->uiEndCutTime == 0 ) { pC->uiEndCutTime = pC->InputFileProperties.uiClipDuration; } /* Force a re-set to check validity of parameters */ VerifyRates.OutputVideoBitrate = pC->uiVideoBitrate; VerifyRates.OutputAudioBitrate = pC->uiAudioBitrate; VerifyRates.BeginCutTime = pC->uiBeginCutTime; VerifyRates.EndCutTime = pC->uiEndCutTime; VerifyRates.OutputFileSize = pC->uiMaxFileSize; VerifyRates.OutputVideoTimescale = pC->outputVideoTimescale; err = M4MCS_setEncodingParams(pContext, &VerifyRates); /** * Check parameters consistency */ if( err != M4NO_ERROR ) { M4OSA_TRACE1_0("M4MCS_checkParamsAndStart : invalid parameter found"); return err; } /** * All is OK : update state automaton */ pC->uiEncVideoBitrate = pC->uiVideoBitrate; pC->AudioEncParams.Bitrate = pC->uiAudioBitrate; #ifdef M4MCS_WITH_FAST_OPEN /** * Remake the open if it was done in fast mode */ if( M4OSA_TRUE == pC->bFileOpenedInFastMode ) { /* Close the file opened in fast mode */ M4MCS_intCleanUp_ReadersDecoders(pC); pC->State = M4MCS_kState_CREATED; /* Reopen it in normal mode */ err = M4MCS_open(pContext, pC->pInputFile, pC->InputFileType, pC->pOutputFile, pC->pTemporaryFile); if( err != M4NO_ERROR ) { M4OSA_TRACE1_1( "M4MCS_checkParamsAndStart : M4MCS_Open returns 0x%x", err); return err; } } #endif /* M4MCS_WITH_FAST_OPEN */ pC->State = M4MCS_kState_READY; return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intStepSet(M4MCS_InternalContext* pC) ****************************************************************************** */ static M4OSA_ERR M4MCS_intStepSet( M4MCS_InternalContext *pC ) { M4OSA_ERR err; M4ENCODER_Header *encHeader; /** * Prepare the video decoder */ err = M4MCS_intPrepareVideoDecoder(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intStepSet(): M4MCS_intPrepareVideoDecoder() returns 0x%x", err); return err; } if( ( pC->InputFileProperties.VideoStreamType == M4VIDEOEDITING_kH264) && (pC->EncodingVideoFormat == M4ENCODER_kNULL) ) { pC->bH264Trim = M4OSA_TRUE; } /** * Prepare the video encoder */ err = M4MCS_intPrepareVideoEncoder(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intStepSet(): M4MCS_intPrepareVideoEncoder() returns 0x%x", err); return err; } if( ( pC->uiBeginCutTime != 0) && (pC->InputFileProperties.VideoStreamType == M4VIDEOEDITING_kH264) && (pC->EncodingVideoFormat == M4ENCODER_kNULL) ) { err = pC->pVideoEncoderGlobalFcts->pFctSetOption(pC->pViEncCtxt, M4ENCODER_kOptionID_H264ProcessNALUContext, (M4OSA_DataOption)pC->m_pInstance); if( err != M4NO_ERROR ) { M4OSA_TRACE1_1("M4MCS_intStetSet :pFctSetOption failed (err 0x%x)", err); return err; } err = pC->pVideoEncoderGlobalFcts->pFctSetOption(pC->pViEncCtxt, M4ENCODER_kOptionID_SetH264ProcessNALUfctsPtr, (M4OSA_DataOption) &H264MCS_ProcessEncodedNALU); if( err != M4NO_ERROR ) { M4OSA_TRACE1_1("M4MCS_intStetSet :pFctSetOption failed (err 0x%x)", err); return err; } err = pC->pVideoEncoderGlobalFcts->pFctGetOption(pC->pViEncCtxt, M4ENCODER_kOptionID_EncoderHeader, (M4OSA_DataOption) &encHeader); if( ( M4NO_ERROR != err) || (M4OSA_NULL == encHeader->pBuf) ) { M4OSA_TRACE1_1( "M4MCS_close: failed to get the encoder header (err 0x%x)", err); /**< no return here, we still have stuff to deallocate after close, even if it fails.*/ } else { // Handle DSI first bits #define SPS_START_POS 6 pC->m_pInstance->m_encoderSPSSize = ( encHeader->pBuf[SPS_START_POS] << 8) + encHeader->pBuf[SPS_START_POS + 1]; pC->m_pInstance->m_pEncoderSPS = (M4OSA_UInt8 *)(encHeader->pBuf) + SPS_START_POS + 2; pC->m_pInstance->m_encoderPPSSize = ( encHeader->pBuf[SPS_START_POS + 3 + pC->m_pInstance->m_encoderSPSSize] << 8) + encHeader->pBuf[SPS_START_POS + 4 + pC->m_pInstance->m_encoderSPSSize]; pC->m_pInstance->m_pEncoderPPS = (M4OSA_UInt8 *)encHeader->pBuf + SPS_START_POS + 5 + pC->m_pInstance->m_encoderSPSSize; /* Check the DSI integrity */ if( encHeader->Size != (pC->m_pInstance->m_encoderSPSSize + pC->m_pInstance->m_encoderPPSSize + 5 + SPS_START_POS) ) { M4OSA_TRACE1_3( "!!! M4MCS_intStepSet ERROR : invalid SPS / PPS %d %d %d", encHeader->Size, pC->m_pInstance->m_encoderSPSSize, pC->m_pInstance->m_encoderPPSSize); return M4ERR_PARAMETER; } } } /** * Prepare audio processing */ err = M4MCS_intPrepareAudioProcessing(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intStepSet(): M4MCS_intPrepareAudioProcessing() returns 0x%x", err); return err; } /** * Prepare the writer */ err = M4MCS_intPrepareWriter(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intStepSet(): M4MCS_intPrepareWriter() returns 0x%x", err); return err; } /** * Jump the audio stream to the begin cut time (all AUs are RAP) * Must be done after the 3gpp writer init, because it may write the first * audio AU in some cases */ err = M4MCS_intPrepareAudioBeginCut(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intStepSet(): M4MCS_intPrepareAudioBeginCut() returns 0x%x", err); return err; } /** * Update state automaton */ if( 0 == pC->uiBeginCutTime ) { pC->dViDecStartingCts = 0.0; /** * No begin cut, do the encoding */ pC->State = M4MCS_kState_PROCESSING; } else { /** * Remember that we must start the decode/encode process at the begin cut time */ pC->dViDecStartingCts = (M4OSA_Double)pC->uiBeginCutTime; /** * Jumping */ pC->State = M4MCS_kState_BEGINVIDEOJUMP; } /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_intStepSet(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intPrepareVideoDecoder(M4MCS_InternalContext* pC); * @brief Prepare the video decoder. * @param pC (IN) MCS private context * @return M4NO_ERROR No error * @return M4MCS_ERR_H263_PROFILE_NOT_SUPPORTED * @return Any error returned by an underlaying module ****************************************************************************** */ static M4OSA_ERR M4MCS_intPrepareVideoDecoder( M4MCS_InternalContext *pC ) { M4OSA_ERR err; M4OSA_Void *decoderUserData; M4DECODER_OutputFilter FilterOption; if( pC->novideo ) return M4NO_ERROR; /** * Create the decoder, if it has not been created yet (to get video properties for example) */ if( M4OSA_NULL == pC->pViDecCtxt ) { #ifdef M4VSS_ENABLE_EXTERNAL_DECODERS decoderUserData = pC->m_pCurrentVideoDecoderUserData; #else decoderUserData = M4OSA_NULL; #endif /* M4VSS_ENABLE_EXTERNAL_DECODERS ? */ err = pC->m_pVideoDecoder->m_pFctCreate(&pC->pViDecCtxt, &pC->pReaderVideoStream->m_basicProperties, pC->m_pReader, pC->m_pReaderDataIt, &pC->ReaderVideoAU, decoderUserData); if( (M4OSA_UInt32)(M4ERR_DECODER_H263_PROFILE_NOT_SUPPORTED) == err ) { /** * Our decoder is not compatible with H263 profile other than 0. * So it returns this internal error code. * We translate it to our own error code */ M4OSA_TRACE1_0("M4MCS_intPrepareVideoDecoder:\ returning M4MCS_ERR_H263_PROFILE_NOT_SUPPORTED"); return M4MCS_ERR_H263_PROFILE_NOT_SUPPORTED; } else if( M4NO_ERROR != err ) { M4OSA_TRACE1_1("M4MCS_intPrepareVideoDecoder:\ m_pVideoDecoder->m_pFctCreate returns 0x%x", err); return err; } if( M4VIDEOEDITING_kH264 == pC->InputFileProperties.VideoStreamType ) { FilterOption.m_pFilterFunction = (M4OSA_Void *) &M4VIFI_ResizeBilinearYUV420toYUV420; FilterOption.m_pFilterUserData = M4OSA_NULL; err = pC->m_pVideoDecoder->m_pFctSetOption(pC->pViDecCtxt, M4DECODER_kOptionID_OutputFilter, (M4OSA_DataOption) &FilterOption); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1("M4MCS_intPrepareVideoDecoder:\ m_pVideoDecoder->m_pFctSetOption returns 0x%x", err); return err; } } } /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_intPrepareVideoDecoder(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intPrepareVideoEncoder(M4MCS_InternalContext* pC); * @brief Prepare the video encoder. * @param pC (IN) MCS private context * @return M4NO_ERROR No error * @return Any error returned by an underlaying module ****************************************************************************** */ static M4OSA_ERR M4MCS_intPrepareVideoEncoder( M4MCS_InternalContext *pC ) { M4OSA_ERR err; M4ENCODER_AdvancedParams EncParams; /**< Encoder advanced parameters */ M4ENCODER_Params EncParams1; M4OSA_Double dFrameRate; /**< tmp variable */ if( pC->novideo ) return M4NO_ERROR; if( pC->EncodingVideoFormat == M4ENCODER_kNULL ) { /* Approximative cts increment */ pC->dCtsIncrement = 1000.0 / pC->pReaderVideoStream->m_averageFrameRate; if( pC->uiBeginCutTime == 0 ) { M4OSA_TRACE3_0( "M4MCS_intPrepareVideoEncoder(): Null encoding, do nothing."); return M4NO_ERROR; } else { M4OSA_TRACE3_0( "M4MCS_intPrepareVideoEncoder(): Null encoding, I-frame defaults."); /* Set useful parameters to encode the first I-frame */ EncParams.InputFormat = M4ENCODER_kIYUV420; EncParams.videoProfile = pC->encodingVideoProfile; EncParams.videoLevel= pC->encodingVideoLevel; switch( pC->InputFileProperties.VideoStreamType ) { case M4VIDEOEDITING_kH263: EncParams.Format = M4ENCODER_kH263; break; case M4VIDEOEDITING_kMPEG4: EncParams.Format = M4ENCODER_kMPEG4; break; case M4VIDEOEDITING_kH264: EncParams.Format = M4ENCODER_kH264; break; default: M4OSA_TRACE1_1("M4MCS_intPrepareVideoEncoder: unknown encoding video format\ (%d), returning M4MCS_WAR_MEDIATYPE_NOT_SUPPORTED", pC->InputFileProperties.VideoStreamType); return M4MCS_WAR_MEDIATYPE_NOT_SUPPORTED; } EncParams.FrameWidth = pC->EncodingWidth; EncParams.FrameHeight = pC->EncodingHeight; EncParams.Bitrate = pC->uiEncVideoBitrate; EncParams.bInternalRegulation = M4OSA_FALSE; /* do not constrain the I-frame */ EncParams.FrameRate = pC->EncodingVideoFramerate; /* Other encoding settings (quite all dummy...) */ 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 = 5; /* initial QP = 5 */ EncParams.bDataPartitioning = M4OSA_FALSE; /* no data partitioning */ /* Rate factor */ EncParams.uiTimeScale = pC->InputFileProperties.uiVideoTimeScale; EncParams.uiRateFactor = 1; } } else { M4OSA_TRACE3_0( "M4MCS_intPrepareVideoEncoder(): Normal encoding, set full config."); /** * Set encoder shell parameters according to MCS settings */ EncParams.Format = pC->EncodingVideoFormat; EncParams.InputFormat = M4ENCODER_kIYUV420; EncParams.videoProfile = pC->encodingVideoProfile; EncParams.videoLevel= pC->encodingVideoLevel; /** * Video frame size */ EncParams.FrameWidth = pC->EncodingWidth; EncParams.FrameHeight = pC->EncodingHeight; /** * Video bitrate has been previously computed */ EncParams.Bitrate = pC->uiEncVideoBitrate; /** * MCS use the "true" core internal bitrate regulation */ EncParams.bInternalRegulation = M4OSA_TRUE; /** * Other encoder settings */ 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 */ /** * Video encoder frame rate and rate factor */ EncParams.FrameRate = pC->EncodingVideoFramerate; EncParams.uiTimeScale = pC->outputVideoTimescale; switch( pC->EncodingVideoFramerate ) { case M4ENCODER_k5_FPS: dFrameRate = 5.0; break; case M4ENCODER_k7_5_FPS: dFrameRate = 7.5; break; case M4ENCODER_k10_FPS: dFrameRate = 10.0; break; case M4ENCODER_k12_5_FPS: dFrameRate = 12.5; break; case M4ENCODER_k15_FPS: dFrameRate = 15.0; break; case M4ENCODER_k20_FPS: /**< MPEG-4 only */ dFrameRate = 20.0; break; case M4ENCODER_k25_FPS: /**< MPEG-4 only */ dFrameRate = 25.0; break; case M4ENCODER_k30_FPS: dFrameRate = 30.0; break; default: M4OSA_TRACE1_1( "M4MCS_intPrepareVideoEncoder: unknown encoding video frame rate\ (0x%x), returning M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_RATE", pC->EncodingVideoFramerate); return M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_RATE; } /** * Compute the number of milliseconds between two frames */ if( M4ENCODER_kH263 == EncParams.Format ) { pC->dCtsIncrement = 1001.0 / dFrameRate; } else /**< MPEG4 or H.264 */ { pC->dCtsIncrement = 1000.0 / dFrameRate; } } /** * Limit the video bitrate according to encoder profile * and level */ err = M4MCS_intLimitBitratePerCodecProfileLevel(&EncParams); if (M4NO_ERROR != err) { M4OSA_TRACE1_1( "M4MCS_intPrepareVideoEncoder: limit bitrate returned err \ 0x%x", err); return err; } /** * Create video encoder */ err = pC->pVideoEncoderGlobalFcts->pFctInit(&pC->pViEncCtxt, pC->pWriterDataFcts, \ M4MCS_intApplyVPP, pC, pC->pCurrentVideoEncoderExternalAPI, \ pC->pCurrentVideoEncoderUserData); /**< We put the MCS context in place of the VPP context */ if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareVideoEncoder: EncoderInt->pFctInit returns 0x%x", err); return err; } pC->encoderState = M4MCS_kEncoderClosed; if( M4OSA_TRUE == pC->bH264Trim ) //if((M4ENCODER_kNULL == pC->EncodingVideoFormat) // && (M4VIDEOEDITING_kH264 == pC->InputFileProperties.VideoStreamType)) { EncParams1.InputFormat = EncParams.InputFormat; //EncParams1.InputFrameWidth = EncParams.InputFrameWidth; //EncParams1.InputFrameHeight = EncParams.InputFrameHeight; EncParams1.FrameWidth = EncParams.FrameWidth; EncParams1.FrameHeight = EncParams.FrameHeight; EncParams1.videoProfile= EncParams.videoProfile; EncParams1.videoLevel= EncParams.videoLevel; EncParams1.Bitrate = EncParams.Bitrate; EncParams1.FrameRate = EncParams.FrameRate; EncParams1.Format = M4ENCODER_kH264; //EncParams.Format; M4OSA_TRACE1_2("mcs encoder open profile :%d, level %d", EncParams1.videoProfile, EncParams1.videoLevel); err = pC->pVideoEncoderGlobalFcts->pFctOpen(pC->pViEncCtxt, &pC->WriterVideoAU, &EncParams1); } else { M4OSA_TRACE1_2("mcs encoder open Adv profile :%d, level %d", EncParams.videoProfile, EncParams.videoLevel); err = pC->pVideoEncoderGlobalFcts->pFctOpen(pC->pViEncCtxt, &pC->WriterVideoAU, &EncParams); } if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareVideoEncoder: EncoderInt->pFctOpen returns 0x%x", err); return err; } pC->encoderState = M4MCS_kEncoderStopped; if( M4OSA_NULL != pC->pVideoEncoderGlobalFcts->pFctStart ) { err = pC->pVideoEncoderGlobalFcts->pFctStart(pC->pViEncCtxt); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareVideoEncoder: EncoderInt->pFctStart returns 0x%x", err); return err; } } pC->encoderState = M4MCS_kEncoderRunning; /******************************/ /* Video resize management */ /******************************/ /** * Compare video input size and video output size to check if resize is needed */ if( ( (M4OSA_UInt32)EncParams.FrameWidth != pC->pReaderVideoStream->m_videoWidth) || ((M4OSA_UInt32)EncParams.FrameHeight != pC->pReaderVideoStream->m_videoHeight) ) { /** * Allocate the intermediate video plane that will receive the decoded image before resizing */ pC->pPreResizeFrame = (M4VIFI_ImagePlane *)M4OSA_32bitAlignedMalloc(3 * sizeof(M4VIFI_ImagePlane), M4MCS, (M4OSA_Char *)"m_pPreResizeFrame"); if( M4OSA_NULL == pC->pPreResizeFrame ) { M4OSA_TRACE1_0("M4MCS_intPrepareVideoEncoder():\ unable to allocate m_pPreResizeFrame, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } pC->pPreResizeFrame[0].pac_data = M4OSA_NULL; pC->pPreResizeFrame[1].pac_data = M4OSA_NULL; pC->pPreResizeFrame[2].pac_data = M4OSA_NULL; /** * Allocate the Y plane */ pC->pPreResizeFrame[0].u_topleft = 0; pC->pPreResizeFrame[0].u_width = pC->pReaderVideoStream-> m_videoWidth; /**< input width */ pC->pPreResizeFrame[0].u_height = pC->pReaderVideoStream-> m_videoHeight; /**< input height */ pC->pPreResizeFrame[0].u_stride = pC-> pPreResizeFrame[0].u_width; /**< simple case: stride equals width */ pC->pPreResizeFrame[0].pac_data = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(pC->pPreResizeFrame[0].u_stride \ *pC->pPreResizeFrame[0].u_height, M4MCS, (M4OSA_Char *)"m_pPreResizeFrame[0].pac_data"); if( M4OSA_NULL == pC->pPreResizeFrame[0].pac_data ) { M4OSA_TRACE1_0( "M4MCS_intPrepareVideoEncoder():\ unable to allocate m_pPreResizeFrame[0].pac_data, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } /** * Allocate the U plane */ pC->pPreResizeFrame[1].u_topleft = 0; pC->pPreResizeFrame[1].u_width = pC->pPreResizeFrame[0].u_width >> 1; /**< U width is half the Y width */ pC->pPreResizeFrame[1].u_height = pC->pPreResizeFrame[0].u_height >> 1; /**< U height is half the Y height */ pC->pPreResizeFrame[1].u_stride = pC-> pPreResizeFrame[1].u_width; /**< simple case: stride equals width */ pC->pPreResizeFrame[1].pac_data = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(pC->pPreResizeFrame[1].u_stride \ *pC->pPreResizeFrame[1].u_height, M4MCS, (M4OSA_Char *)"m_pPreResizeFrame[1].pac_data"); if( M4OSA_NULL == pC->pPreResizeFrame[1].pac_data ) { M4OSA_TRACE1_0( "M4MCS_intPrepareVideoEncoder():\ unable to allocate m_pPreResizeFrame[1].pac_data, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } /** * Allocate the V plane */ pC->pPreResizeFrame[2].u_topleft = 0; pC->pPreResizeFrame[2].u_width = pC-> pPreResizeFrame[1].u_width; /**< V width equals U width */ pC->pPreResizeFrame[2].u_height = pC-> pPreResizeFrame[1].u_height; /**< V height equals U height */ pC->pPreResizeFrame[2].u_stride = pC-> pPreResizeFrame[2].u_width; /**< simple case: stride equals width */ pC->pPreResizeFrame[2].pac_data = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(pC->pPreResizeFrame[2].u_stride \ *pC->pPreResizeFrame[2].u_height, M4MCS, (M4OSA_Char *)"m_pPreResizeFrame[1].pac_data"); if( M4OSA_NULL == pC->pPreResizeFrame[2].pac_data ) { M4OSA_TRACE1_0( "M4MCS_intPrepareVideoEncoder():\ unable to allocate m_pPreResizeFrame[2].pac_data, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } } /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_intPrepareVideoEncoder(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intPrepareAudioProcessing(M4MCS_InternalContext* pC); * @brief Prepare the AAC decoder, the SRC and the AMR-NB encoder and the MP3 encoder. * @param pC (IN) MCS private context * @return M4NO_ERROR No error * @return Any error returned by an underlaying module ****************************************************************************** */ static M4OSA_ERR M4MCS_intPrepareAudioProcessing( M4MCS_InternalContext *pC ) { M4OSA_ERR err; 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 */ #ifdef MCS_DUMP_PCM_TO_FILE file_au_reader = fopen("mcs_ReaderOutput.raw", "wb"); file_pcm_decoder = fopen("mcs_DecoderOutput.pcm", "wb"); file_pcm_encoder = fopen("mcs_EncoderInput.pcm", "wb"); #endif if( pC->noaudio ) return M4NO_ERROR; if( pC->AudioEncParams.Format == M4ENCODER_kAudioNULL ) { M4OSA_TRACE3_0( "M4MCS_intPrepareAudioProcessing(): Null encoding, do nothing."); return M4NO_ERROR; } /* ________________________________ */ /*| |*/ /*| Create and "start" the decoder |*/ /*|________________________________|*/ if( M4OSA_NULL == pC->m_pAudioDecoder ) { M4OSA_TRACE1_0( "M4MCS_intPrepareAudioProcessing(): Fails to initiate the audio decoder."); return M4MCS_ERR_AUDIO_CONVERSION_FAILED; } if( M4OSA_NULL == pC->pAudioDecCtxt ) { err = pC->m_pAudioDecoder->m_pFctCreateAudioDec(&pC->pAudioDecCtxt, pC->pReaderAudioStream, pC->m_pCurrentAudioDecoderUserData); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareVideoDecoder: m_pAudioDecoder->m_pFctCreateAudioDec returns 0x%x", err); return err; } } if( M4VIDEOEDITING_kAMR_NB == pC->InputFileProperties.AudioStreamType ) { /* AMR DECODER CONFIGURATION */ /* nothing specific to do */ } else if( M4VIDEOEDITING_kEVRC == pC->InputFileProperties.AudioStreamType ) { /* EVRC DECODER CONFIGURATION */ /* nothing specific to do */ } else if( M4VIDEOEDITING_kMP3 == pC->InputFileProperties.AudioStreamType ) { /* MP3 DECODER CONFIGURATION */ /* nothing specific to do */ } else { /* AAC DECODER CONFIGURATION */ M4_AacDecoderConfig AacDecParam; AacDecParam.m_AACDecoderProfile = AAC_kAAC; AacDecParam.m_DownSamplingMode = AAC_kDS_OFF; if( pC->AudioEncParams.Format == M4ENCODER_kAMRNB ) { AacDecParam.m_OutputMode = AAC_kMono; } else { /* For this version, we encode only in AAC */ if( M4ENCODER_kMono == pC->AudioEncParams.ChannelNum ) { AacDecParam.m_OutputMode = AAC_kMono; } else { AacDecParam.m_OutputMode = AAC_kStereo; } } pC->m_pAudioDecoder->m_pFctSetOptionAudioDec(pC->pAudioDecCtxt, M4AD_kOptionID_UserParam, (M4OSA_DataOption) &AacDecParam); } pC->m_pAudioDecoder->m_pFctSetOptionAudioDec(pC->pAudioDecCtxt, M4AD_kOptionID_3gpReaderInterface, (M4OSA_DataOption) pC->m_pReaderDataIt); pC->m_pAudioDecoder->m_pFctSetOptionAudioDec(pC->pAudioDecCtxt, M4AD_kOptionID_AudioAU, (M4OSA_DataOption) &pC->ReaderAudioAU); if( pC->m_pAudioDecoder->m_pFctStartAudioDec != M4OSA_NULL ) { /* Not implemented in all decoders */ err = pC->m_pAudioDecoder->m_pFctStartAudioDec(pC->pAudioDecCtxt); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareVideoDecoder: m_pAudioDecoder->m_pFctStartAudioDec returns 0x%x", err); return err; } } /** * Allocate output buffer for the audio decoder */ pC->InputFileProperties.uiDecodedPcmSize = pC->pReaderAudioStream->m_byteFrameLength * pC->pReaderAudioStream->m_byteSampleSize * pC->pReaderAudioStream->m_nbChannels; if( pC->InputFileProperties.uiDecodedPcmSize > 0 ) { pC->AudioDecBufferOut.m_bufferSize = pC->InputFileProperties.uiDecodedPcmSize; pC->AudioDecBufferOut.m_dataAddress = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(pC->AudioDecBufferOut.m_bufferSize \ *sizeof(short), M4MCS, (M4OSA_Char *)"AudioDecBufferOut.m_bufferSize"); } if( M4OSA_NULL == pC->AudioDecBufferOut.m_dataAddress ) { M4OSA_TRACE1_0( "M4MCS_intPrepareVideoDecoder():\ unable to allocate AudioDecBufferOut.m_dataAddress, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } /* _________________________ */ /*| |*/ /*| Set the SSRC parameters |*/ /*|_________________________|*/ switch( pC->pReaderAudioStream->m_samplingFrequency ) { 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( "M4MCS_intPrepareVideoDecoder: invalid input AAC sampling frequency (%d Hz),\ returning M4MCS_ERR_INVALID_AAC_SAMPLING_FREQUENCY", pC->pReaderAudioStream->m_samplingFrequency); return M4MCS_ERR_INVALID_AAC_SAMPLING_FREQUENCY; } if( 1 == pC->pReaderAudioStream->m_nbChannels ) { ssrcParams.SSRC_NrOfChannels = LVM_MONO; } else { ssrcParams.SSRC_NrOfChannels = LVM_STEREO; } /*FlB 26.02.2009: add mp3 as output format*/ if( pC->AudioEncParams.Format == M4ENCODER_kAAC || pC->AudioEncParams.Format == M4ENCODER_kMP3 ) { switch( pC->AudioEncParams.Frequency ) { case M4ENCODER_k8000Hz: ssrcParams.SSRC_Fs_Out = LVM_FS_8000; break; case M4ENCODER_k11025Hz: ssrcParams.SSRC_Fs_Out = LVM_FS_11025; break; case M4ENCODER_k12000Hz: ssrcParams.SSRC_Fs_Out = LVM_FS_12000; break; case M4ENCODER_k16000Hz: ssrcParams.SSRC_Fs_Out = LVM_FS_16000; break; case M4ENCODER_k22050Hz: ssrcParams.SSRC_Fs_Out = LVM_FS_22050; break; case M4ENCODER_k24000Hz: ssrcParams.SSRC_Fs_Out = LVM_FS_24000; break; case M4ENCODER_k32000Hz: ssrcParams.SSRC_Fs_Out = LVM_FS_32000; break; case M4ENCODER_k44100Hz: ssrcParams.SSRC_Fs_Out = LVM_FS_44100; break; case M4ENCODER_k48000Hz: ssrcParams.SSRC_Fs_Out = LVM_FS_48000; break; default: M4OSA_TRACE1_1( "M4MCS_intPrepareAudioProcessing: invalid output AAC sampling frequency \ (%d Hz), returning M4MCS_ERR_INVALID_AAC_SAMPLING_FREQUENCY", pC->AudioEncParams.Frequency); return M4MCS_ERR_INVALID_AAC_SAMPLING_FREQUENCY; break; } } else { ssrcParams.SSRC_Fs_Out = LVM_FS_8000; } 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( "M4MCS_intPrepareAudioProcessing:\ Error code %d returned by the SSRC_GetNrSamples function", ReturnStatus); return M4MCS_ERR_AUDIO_CONVERSION_FAILED; } NrSamplesMin = (LVM_INT16)((ssrcParams.NrSamplesIn > ssrcParams.NrSamplesOut) ? ssrcParams.NrSamplesOut : ssrcParams.NrSamplesIn); while( NrSamplesMin < M4MCS_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); /** * Allocate buffer for the input of the SSRC */ pC->pSsrcBufferIn = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(pC->iSsrcNbSamplIn * sizeof(short) \ *pC->pReaderAudioStream->m_nbChannels, M4MCS, (M4OSA_Char *)"pSsrcBufferIn"); if( M4OSA_NULL == pC->pSsrcBufferIn ) { M4OSA_TRACE1_0( "M4MCS_intPrepareVideoDecoder():\ unable to allocate pSsrcBufferIn, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } pC->pPosInSsrcBufferIn = (M4OSA_MemAddr8)pC->pSsrcBufferIn; /** * Allocate buffer for the output of the SSRC */ pC->pSsrcBufferOut = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(pC->iSsrcNbSamplOut * sizeof(short) \ *pC->pReaderAudioStream->m_nbChannels, M4MCS, (M4OSA_Char *)"pSsrcBufferOut"); if( M4OSA_NULL == pC->pSsrcBufferOut ) { M4OSA_TRACE1_0( "M4MCS_intPrepareVideoDecoder():\ unable to allocate pSsrcBufferOut, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } pC->pLVAudioResampler = LVAudioResamplerCreate( 16, /*gInputParams.lvBTChannelCount*/ (M4OSA_Int16)pC->InputFileProperties.uiNbChannels/*ssrcParams.SSRC_NrOfChannels*/, (M4OSA_Int32)(pC->AudioEncParams.Frequency)/*ssrcParams.SSRC_Fs_Out*/, 1); if( M4OSA_NULL == pC->pLVAudioResampler) { return M4ERR_ALLOC; } LVAudiosetSampleRate(pC->pLVAudioResampler, /*gInputParams.lvInSampleRate*/ /*pC->pAddedClipCtxt->pSettings->ClipProperties.uiSamplingFrequency*/ pC->InputFileProperties.uiSamplingFrequency/*ssrcParams.SSRC_Fs_In*/); LVAudiosetVolume(pC->pLVAudioResampler, (M4OSA_Int16)(0x1000 /* 0x7fff */), (M4OSA_Int16)(0x1000/*0x7fff*/)); /* ________________________ */ /*| |*/ /*| Init the audio encoder |*/ /*|________________________|*/ /* Initialise the audio encoder */ err = pC->pAudioEncoderGlobalFcts->pFctInit(&pC->pAudioEncCtxt, pC->pCurrentAudioEncoderUserData); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareAudioProcessing: pAudioEncoderGlobalFcts->pFctInit returns 0x%x", err); return err; } /* Open the audio encoder */ err = pC->pAudioEncoderGlobalFcts->pFctOpen(pC->pAudioEncCtxt, &pC->AudioEncParams, &pC->pAudioEncDSI, M4OSA_NULL /* no grabbing */); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareAudioProcessing: pAudioEncoderGlobalFcts->pFctOpen returns 0x%x", err); return err; } /* Allocate the input buffer for the audio encoder */ switch( pC->AudioEncParams.Format ) { case M4ENCODER_kAMRNB: pC->audioEncoderGranularity = M4MCS_PCM_AMR_GRANULARITY_SAMPLES; break; case M4ENCODER_kAAC: pC->audioEncoderGranularity = M4MCS_PCM_AAC_GRANULARITY_SAMPLES; break; /*FlB 26.02.2009: add mp3 as output format*/ case M4ENCODER_kMP3: pC->audioEncoderGranularity = M4MCS_PCM_MP3_GRANULARITY_SAMPLES; break; default: break; } if( M4ENCODER_kMono == pC->AudioEncParams.ChannelNum ) pC->audioEncoderGranularity *= sizeof(short); else pC->audioEncoderGranularity *= sizeof(short) * 2; pC->pPosInAudioEncoderBuffer = M4OSA_NULL; pC->pAudioEncoderBuffer = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(pC->audioEncoderGranularity, M4MCS, (M4OSA_Char *)"pC->pAudioEncoderBuffer"); /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_intPrepareAudioProcessing(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intPrepareWriter(M4MCS_InternalContext* pC); * @brief Prepare the writer. * @param pC (IN) MCS private context * @return M4NO_ERROR No error * @return Any error returned by an underlaying module ****************************************************************************** */ static M4OSA_ERR M4MCS_intPrepareWriter( M4MCS_InternalContext *pC ) { M4OSA_ERR err; M4OSA_UInt32 uiVersion; /**< To write component version in 3gp writer */ M4OSA_MemAddr8 pDSI = M4OSA_NULL; /**< To create the Decoder Specific Info */ M4SYS_StreamIDValue optionValue; /**< For the setoption calls */ M4OSA_UInt32 TargetedFileSize; M4OSA_Bool bMULPPSSPS = M4OSA_FALSE; /** * Init the writer */ err = pC->pWriterGlobalFcts->pFctOpen(&pC->pWriterContext, pC->pOutputFile, pC->pOsaFileWritPtr, pC->pTemporaryFile, pC->pOsaFileReadPtr); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: pWriterGlobalFcts->pFctOpen returns 0x%x", err); return err; } /** * Link to the writer context in the writer interface */ pC->pWriterDataFcts->pWriterContext = pC->pWriterContext; /** * Set the product description string in the written file */ err = pC->pWriterGlobalFcts->pFctSetOption(pC->pWriterContext, M4WRITER_kEmbeddedString, (M4OSA_DataOption)"NXP-SW : MCS "); if( ( M4NO_ERROR != err) && (( (M4OSA_UInt32)M4ERR_BAD_OPTION_ID) != err) ) /* this option may not be implemented by some writers */ { M4OSA_TRACE1_1( "M4MCS_intPrepareWriter:\ pWriterGlobalFcts->pFctSetOption(M4WRITER_kEmbeddedString) returns 0x%x", err); return err; } /** * Set the product version in the written file */ uiVersion = M4VIDEOEDITING_VERSION_MAJOR * 100 + M4VIDEOEDITING_VERSION_MINOR * 10 + M4VIDEOEDITING_VERSION_REVISION; err = pC->pWriterGlobalFcts->pFctSetOption(pC->pWriterContext, M4WRITER_kEmbeddedVersion, (M4OSA_DataOption) &uiVersion); if( ( M4NO_ERROR != err) && (( (M4OSA_UInt32)M4ERR_BAD_OPTION_ID) != err) ) /* this option may not be implemented by some writers */ { M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: \ pWriterGlobalFcts->pFctSetOption(M4WRITER_kEmbeddedVersion) returns 0x%x", err); return err; } /** * If there is a video input, allocate and fill the video stream structures for the writer */ if( pC->novideo == M4OSA_FALSE ) { /** * Fill Video properties structure for the AddStream method */ pC->WriterVideoStreamInfo.height = pC->EncodingHeight; pC->WriterVideoStreamInfo.width = pC->EncodingWidth; pC->WriterVideoStreamInfo.fps = 0; /**< Not used by the shell/core writer */ pC->WriterVideoStreamInfo.Header.pBuf = M4OSA_NULL; /**< Will be updated later */ pC->WriterVideoStreamInfo.Header.Size = 0; /**< Will be updated later */ /** * Fill Video stream description structure for the AddStream method */ switch( pC->EncodingVideoFormat ) { case M4ENCODER_kMPEG4: pC->WriterVideoStream.streamType = M4SYS_kMPEG_4; break; case M4ENCODER_kH263: pC->WriterVideoStream.streamType = M4SYS_kH263; break; case M4ENCODER_kH264: pC->WriterVideoStream.streamType = M4SYS_kH264; break; case M4ENCODER_kNULL: switch( pC->InputFileProperties.VideoStreamType ) { case M4VIDEOEDITING_kMPEG4: pC->WriterVideoStream.streamType = M4SYS_kMPEG_4; break; case M4VIDEOEDITING_kH263: pC->WriterVideoStream.streamType = M4SYS_kH263; break; case M4VIDEOEDITING_kH264: pC->WriterVideoStream.streamType = M4SYS_kH264; break; default: M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: case input=M4ENCODER_kNULL, \ unknown format (0x%x),\ returning M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FORMAT", pC->EncodingVideoFormat); return M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FORMAT; } break; default: /**< It should never happen, already tested */ M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: unknown format (0x%x),\ returning M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FORMAT", pC->EncodingVideoFormat); return M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FORMAT; } /** * Video bitrate value will be the real value */ pC->WriterVideoStream.averageBitrate = (M4OSA_Int32)pC->uiEncVideoBitrate; pC->WriterVideoStream.maxBitrate = (M4OSA_Int32)pC->uiEncVideoBitrate; /** * most other parameters are "dummy" */ pC->WriterVideoStream.streamID = M4MCS_WRITER_VIDEO_STREAM_ID; pC->WriterVideoStream.timeScale = 0; /**< Not used by the shell/core writer */ pC->WriterVideoStream.profileLevel = 0; /**< Not used by the shell/core writer */ pC->WriterVideoStream.duration = 0; /**< Not used by the shell/core writer */ pC->WriterVideoStream.decoderSpecificInfoSize = sizeof(M4WRITER_StreamVideoInfos); pC->WriterVideoStream.decoderSpecificInfo = (M4OSA_MemAddr32) &(pC->WriterVideoStreamInfo); /** * Update Encoder Header properties for Video stream if needed */ if( M4ENCODER_kH263 == pC->EncodingVideoFormat ) { /** * Creates the H263 DSI */ pC->WriterVideoStreamInfo.Header.Size = 7; /**< H263 output DSI is always 7 bytes */ pDSI = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(7, M4MCS, (M4OSA_Char *)"pC->WriterVideoStreamInfo.Header.pBuf (DSI H263)"); if( M4OSA_NULL == pDSI ) { M4OSA_TRACE1_0("M4MCS_intPrepareWriter(): unable to allocate pDSI (H263),\ returning M4ERR_ALLOC"); return M4ERR_ALLOC; } /** * Vendor is NXP Software: N, X, P, S. */ pDSI[0] = 'N'; pDSI[1] = 'X'; pDSI[2] = 'P'; pDSI[3] = 'S'; /** * Decoder version is 0 */ pDSI[4] = 0; /** * Level is the sixth byte of the DSI. */ switch( pC->EncodingWidth ) { case M4ENCODER_SQCIF_Width: case M4ENCODER_QCIF_Width: if( ( pC->uiEncVideoBitrate <= M4ENCODER_k64_KBPS) && (pC->EncodingVideoFramerate <= M4ENCODER_k15_FPS) ) { pDSI[5] = 10; } else if( ( pC->uiEncVideoBitrate <= M4ENCODER_k128_KBPS) && (pC->EncodingVideoFramerate <= M4ENCODER_k15_FPS) ) { pDSI[5] = 45; } else if( ( pC->uiEncVideoBitrate <= M4ENCODER_k128_KBPS) && (pC->EncodingVideoFramerate <= M4ENCODER_k30_FPS) ) { pDSI[5] = 20; } else if( ( pC->uiEncVideoBitrate <= M4ENCODER_k384_KBPS) && (pC->EncodingVideoFramerate <= M4ENCODER_k30_FPS) ) { pDSI[5] = 30; } else if( ( pC->uiEncVideoBitrate <= M4ENCODER_k800_KBPS/*2048*/) && (pC->EncodingVideoFramerate <= M4ENCODER_k30_FPS) ) { pDSI[5] = 40; } break; case M4ENCODER_CIF_Width: if( ( pC->uiEncVideoBitrate <= M4ENCODER_k128_KBPS) && (pC->EncodingVideoFramerate <= M4ENCODER_k15_FPS) ) { pDSI[5] = 20; } else if( ( pC->uiEncVideoBitrate <= M4ENCODER_k384_KBPS) && (pC->EncodingVideoFramerate <= M4ENCODER_k30_FPS) ) { pDSI[5] = 30; } else if( ( pC->uiEncVideoBitrate <= M4ENCODER_k800_KBPS/*2048*/) && (pC->EncodingVideoFramerate <= M4ENCODER_k30_FPS) ) { pDSI[5] = 40; } break; default: break; } /** * Profile is the seventh byte of the DSI. */ pDSI[6] = 0; pC->WriterVideoStreamInfo.Header.pBuf = pDSI; } else if( M4ENCODER_kNULL == pC->EncodingVideoFormat ) { /* If we copy the stream from the input, we copy its DSI */ pC->WriterVideoStreamInfo.Header.Size = pC->pReaderVideoStream-> m_basicProperties.m_decoderSpecificInfoSize; pC->WriterVideoStreamInfo.Header.pBuf = (M4OSA_MemAddr8)pC->pReaderVideoStream-> m_basicProperties.m_pDecoderSpecificInfo; } /* otherwise (MPEG4), the DSI will be recovered from the encoder later on. */ /*+CRLV6775 - H.264 Trimming */ if( pC->bH264Trim == M4OSA_TRUE ) { bMULPPSSPS = M4OSA_TRUE; err = pC->pWriterGlobalFcts->pFctSetOption(pC->pWriterContext, (M4OSA_UInt32)M4WRITER_kMUL_PPS_SPS, (M4OSA_DataOption) &bMULPPSSPS); if( ( M4NO_ERROR != err) && (( (M4OSA_UInt32)M4ERR_BAD_OPTION_ID) != err) ) /* this option may not be implemented by some writers */ { M4OSA_TRACE1_1( "M4MCS_intPrepareWriter:\ pWriterGlobalFcts->pFctSetOption(M4WRITER_kMUL_PPS_SPS) returns 0x%x", err); return err; } } /*-CRLV6775 - H.264 Trimming */ /** * Add the video stream */ err = pC->pWriterGlobalFcts->pFctAddStream(pC->pWriterContext, &pC->WriterVideoStream); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: pWriterGlobalFcts->pFctAddStream(video) returns 0x%x!", err); return err; } /** * Update AU properties for video stream */ pC->WriterVideoAU.stream = &(pC->WriterVideoStream); pC->WriterVideoAU.dataAddress = M4OSA_NULL; pC->WriterVideoAU.size = 0; pC->WriterVideoAU.CTS = 0; /** Reset time */ pC->WriterVideoAU.DTS = 0; pC->WriterVideoAU.attribute = AU_RAP; pC->WriterVideoAU.nbFrag = 0; /** No fragment */ pC->WriterVideoAU.frag = M4OSA_NULL; /** * Set the writer max video AU size */ optionValue.streamID = M4MCS_WRITER_VIDEO_STREAM_ID; optionValue.value = pC->uiVideoMaxAuSize; err = pC->pWriterGlobalFcts->pFctSetOption(pC->pWriterContext, (M4OSA_UInt32)M4WRITER_kMaxAUSize, (M4OSA_DataOption) &optionValue); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: \ pWriterGlobalFcts->pFctSetOption(M4WRITER_kMaxAUSize, video) returns 0x%x!", err); return err; } /** * Set the writer max video chunk size */ optionValue.value = pC->uiVideoMaxChunckSize; err = pC->pWriterGlobalFcts->pFctSetOption(pC->pWriterContext, (M4OSA_UInt32)M4WRITER_kMaxChunckSize, (M4OSA_DataOption) &optionValue); if( ( M4NO_ERROR != err) && (( (M4OSA_UInt32)M4ERR_BAD_OPTION_ID) != err) ) /* this option may not be implemented by some writers */ { M4OSA_TRACE1_1( "M4MCS_intPrepareWriter:\ pWriterGlobalFcts->pFctSetOption(M4WRITER_kMaxAUSize, video) returns 0x%x!", err); return err; } } /** * If there is an audio input, allocate and fill the audio stream structures for the writer */ if( pC->noaudio == M4OSA_FALSE ) { M4WRITER_StreamAudioInfos streamAudioInfo; streamAudioInfo.nbSamplesPerSec = 0; /**< unused by our shell writer */ streamAudioInfo.nbBitsPerSample = 0; /**< unused by our shell writer */ streamAudioInfo.nbChannels = 1; /**< unused by our shell writer */ pC->WriterAudioStream.averageBitrate = 0; /**< It is not used by the shell, the DSI is taken into account instead */ pC->WriterAudioStream.maxBitrate = 0; /**< Not used by the shell/core writer */ /** * Fill Audio stream description structure for the AddStream method */ switch( pC->AudioEncParams.Format ) { case M4ENCODER_kAMRNB: pC->WriterAudioStream.streamType = M4SYS_kAMR; break; case M4ENCODER_kAAC: pC->WriterAudioStream.streamType = M4SYS_kAAC; pC->WriterAudioStream.averageBitrate = pC->AudioEncParams.Bitrate; pC->WriterAudioStream.maxBitrate = pC->AudioEncParams.Bitrate; break; /*FlB 26.02.2009: add mp3 as output format*/ case M4ENCODER_kMP3: pC->WriterAudioStream.streamType = M4SYS_kMP3; break; case M4ENCODER_kAudioNULL: switch( pC->InputFileProperties.AudioStreamType ) { case M4VIDEOEDITING_kAMR_NB: pC->WriterAudioStream.streamType = M4SYS_kAMR; break; /*FlB 26.02.2009: add mp3 as output format*/ case M4VIDEOEDITING_kMP3: pC->WriterAudioStream.streamType = M4SYS_kMP3; break; case M4VIDEOEDITING_kAAC: case M4VIDEOEDITING_kAACplus: case M4VIDEOEDITING_keAACplus: pC->WriterAudioStream.streamType = M4SYS_kAAC; pC->WriterAudioStream.averageBitrate = pC->AudioEncParams.Bitrate; pC->WriterAudioStream.maxBitrate = pC->AudioEncParams.Bitrate; break; case M4VIDEOEDITING_kEVRC: pC->WriterAudioStream.streamType = M4SYS_kEVRC; break; case M4VIDEOEDITING_kNoneAudio: case M4VIDEOEDITING_kPCM: case M4VIDEOEDITING_kNullAudio: case M4VIDEOEDITING_kUnsupportedAudio: break; } break; default: /**< It should never happen, already tested */ M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: \ unknown format (0x%x), returning M4MCS_ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT", pC->AudioEncParams.Format); return M4MCS_ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT; } /** * MCS produces only AMR-NB output */ pC->WriterAudioStream.streamID = M4MCS_WRITER_AUDIO_STREAM_ID; pC->WriterAudioStream.duration = 0; /**< Not used by the shell/core writer */ pC->WriterAudioStream.profileLevel = 0; /**< Not used by the shell/core writer */ pC->WriterAudioStream.timeScale = pC->AudioEncParams.Frequency; if( pC->AudioEncParams.Format == M4ENCODER_kAudioNULL ) { /* If we copy the stream from the input, we copy its DSI */ streamAudioInfo.Header.Size = pC->pReaderAudioStream-> m_basicProperties.m_decoderSpecificInfoSize; streamAudioInfo.Header.pBuf = (M4OSA_MemAddr8)pC->pReaderAudioStream-> m_basicProperties.m_pDecoderSpecificInfo; } else { if( pC->pAudioEncDSI.pInfo != M4OSA_NULL ) { /* Use the DSI given by the encoder open() */ streamAudioInfo.Header.Size = pC->pAudioEncDSI.infoSize; streamAudioInfo.Header.pBuf = pC->pAudioEncDSI.pInfo; } else { /* Writer will put a default Philips DSI */ streamAudioInfo.Header.Size = 0; streamAudioInfo.Header.pBuf = M4OSA_NULL; } } /** * Our writer shell interface is a little tricky: we put M4WRITER_StreamAudioInfos in the DSI pointer... */ pC->WriterAudioStream.decoderSpecificInfo = (M4OSA_MemAddr32) &streamAudioInfo; /** * Add the audio stream to the writer */ err = pC->pWriterGlobalFcts->pFctAddStream(pC->pWriterContext, &pC->WriterAudioStream); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: pWriterGlobalFcts->pFctAddStream(audio) returns 0x%x", err); return err; } /** * Link the AU and the stream */ pC->WriterAudioAU.stream = &(pC->WriterAudioStream); pC->WriterAudioAU.dataAddress = M4OSA_NULL; pC->WriterAudioAU.size = 0; pC->WriterAudioAU.CTS = 0; /** Reset time */ pC->WriterAudioAU.DTS = 0; pC->WriterAudioAU.attribute = 0; pC->WriterAudioAU.nbFrag = 0; /** No fragment */ pC->WriterAudioAU.frag = M4OSA_NULL; /** * Set the writer audio max AU size */ /* As max bitrate is now 320kbps instead of 128kbps, max AU * size has to be increased adapt the max AU size according to the stream type and the * channels numbers*/ /* After tests, a margin of 3 is taken (2 was not enough and raises to memory overwrite) */ //pC->uiAudioMaxAuSize = M4MCS_AUDIO_MAX_AU_SIZE; switch( pC->WriterAudioStream.streamType ) { case M4SYS_kAMR: pC->uiAudioMaxAuSize = M4MCS_PCM_AMR_GRANULARITY_SAMPLES * (( pC->InputFileProperties.uiNbChannels * sizeof(short)) + 3); break; case M4SYS_kMP3: pC->uiAudioMaxAuSize = M4MCS_PCM_MP3_GRANULARITY_SAMPLES * (( pC->InputFileProperties.uiNbChannels * sizeof(short)) + 3); break; case M4SYS_kAAC: pC->uiAudioMaxAuSize = M4MCS_PCM_AAC_GRANULARITY_SAMPLES * (( pC->InputFileProperties.uiNbChannels * sizeof(short)) + 3); break; /*case M4SYS_kEVRC: pC->uiAudioMaxAuSize = M4MCS_PCM_EVRC_GRANULARITY_SAMPLES* ((pC->InputFileProperties.uiNbChannels * sizeof(short))+3); break;*/ default: /**< It should never happen, already tested */ M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: unknown format (0x%x),\ returning M4MCS_ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT", pC->WriterAudioStream.streamType); return M4MCS_ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT; } optionValue.streamID = M4MCS_WRITER_AUDIO_STREAM_ID; optionValue.value = pC->uiAudioMaxAuSize; err = pC->pWriterGlobalFcts->pFctSetOption(pC->pWriterContext, (M4OSA_UInt32)M4WRITER_kMaxAUSize, (M4OSA_DataOption) &optionValue); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: pWriterGlobalFcts->pFctSetOption(audio,\ M4WRITER_kMaxAUSize) returns 0x%x", err); return err; } optionValue.value = M4MCS_AUDIO_MAX_CHUNK_SIZE; err = pC->pWriterGlobalFcts->pFctSetOption(pC->pWriterContext, (M4OSA_UInt32)M4WRITER_kMaxChunckSize, (M4OSA_DataOption) &optionValue); if( ( M4NO_ERROR != err) && (( (M4OSA_UInt32)M4ERR_BAD_OPTION_ID) != err) ) /* this option may not be implemented by some writers */ { M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: pWriterGlobalFcts->pFctSetOption(audio,\ M4WRITER_kMaxChunckSize) returns 0x%x", err); return err; } } /* * Set the limitation size of the writer */ TargetedFileSize = pC->uiMaxFileSize; /* add 1 kB margin */ if( TargetedFileSize > 8192 ) TargetedFileSize -= 1024; err = pC->pWriterGlobalFcts->pFctSetOption(pC->pWriterContext, (M4OSA_UInt32)M4WRITER_kMaxFileSize, (M4OSA_DataOption) &TargetedFileSize); if( ( M4NO_ERROR != err) && (( (M4OSA_UInt32)M4ERR_BAD_OPTION_ID) != err) ) /* this option may not be implemented by some writers */ { M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: pWriterGlobalFcts->pFctSetOption\ (M4WRITER_kMaxFileSize) returns 0x%x!", err); return err; } /** * Close the stream registering in order to be ready to write data */ err = pC->pWriterGlobalFcts->pFctStartWriting(pC->pWriterContext); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareWriter: pWriterGlobalFcts->pFctStartWriting returns 0x%x", err); return err; } /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_intPrepareWriter(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intPrepareAudioBeginCut(M4MCS_InternalContext* pC); * @brief DO the audio begin cut. * @param pC (IN) MCS private context * @return M4NO_ERROR No error * @return Any error returned by an underlaying module ****************************************************************************** */ static M4OSA_ERR M4MCS_intPrepareAudioBeginCut( M4MCS_InternalContext *pC ) { M4OSA_ERR err; M4OSA_Int32 iCts; M4OSA_UInt32 uiFrameSize; if( pC->noaudio ) return M4NO_ERROR; /** * Check if an audio begin cut is needed */ if( ( M4OSA_NULL == pC->pReaderAudioStream) || (0 == pC->uiBeginCutTime) ) { /** * Return with no error */ M4OSA_TRACE3_0( "M4MCS_intPrepareAudioBeginCut(): returning M4NO_ERROR (a)"); return M4NO_ERROR; } /** * Jump at the begin cut time */ iCts = pC->uiBeginCutTime; err = pC->m_pReader->m_pFctJump(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderAudioStream, &iCts); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareAudioBeginCut: m_pFctJump(Audio) returns 0x%x!", err); return err; } /** * Remember audio begin cut offset */ pC->iAudioCtsOffset = iCts; /** * AMR-NB & EVRC: there may be many frames per AU. * In that case we need to slice the first AU to keep the 20 ms cut precision */ if( ( M4DA_StreamTypeAudioAmrNarrowBand == pC->pReaderAudioStream->m_basicProperties.m_streamType) || (M4DA_StreamTypeAudioEvrc == pC->pReaderAudioStream->m_basicProperties.m_streamType) ) { /** * If the next frame CTS is lower than the begin cut time, * we must read the AU and parse its frames to reach the * nearest to the begin cut */ if( ( iCts + 20) < (M4OSA_Int32)pC->uiBeginCutTime ) { /** * Read the first audio AU after the jump */ err = pC->m_pReaderDataIt->m_pFctGetNextAu(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderAudioStream, &pC->ReaderAudioAU); if( M4WAR_NO_MORE_AU == err ) { M4OSA_TRACE1_0( "M4MCS_intPrepareAudioBeginCut(): m_pReaderDataIt->m_pFctGetNextAu(audio)\ returns M4WAR_NO_MORE_AU! Returning M4NO_ERROR"); return M4NO_ERROR; /**< no fatal error here, we should be able to pursue */ } else if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intPrepareAudioBeginCut(): m_pReaderDataIt->m_pFctGetNextAu(Audio)\ returns 0x%x", err); return err; } /** * While the next AU has a lower CTS than the begin cut time, we advance to the next frame */ while( ( iCts + 20) <= (M4OSA_Int32)pC->uiBeginCutTime ) { /** * Get the size of the frame */ switch( pC->pReaderAudioStream->m_basicProperties.m_streamType ) { case M4DA_StreamTypeAudioAmrNarrowBand: uiFrameSize = M4MCS_intGetFrameSize_AMRNB( pC->ReaderAudioAU.m_dataAddress); break; case M4DA_StreamTypeAudioEvrc: uiFrameSize = M4MCS_intGetFrameSize_EVRC( pC->ReaderAudioAU.m_dataAddress); break; default: uiFrameSize = 0; break; } if( 0 == uiFrameSize ) { /** * Corrupted frame! We get out of this mess! * We don't want to crash here... */ M4OSA_TRACE1_0( "M4MCS_intPrepareAudioBeginCut(): \ M4MCS_intGetFrameSize_xxx returns 0! Returning M4NO_ERROR"); return M4NO_ERROR; /**< no fatal error here, we should be able to pursue */ } /** * Go to the next frame */ pC->ReaderAudioAU.m_dataAddress += uiFrameSize; pC->ReaderAudioAU.m_size -= uiFrameSize; /** * Get the CTS of the next frame */ iCts += 20; /**< AMR, EVRC frame duration is always 20 ms */ pC->ReaderAudioAU.m_CTS = iCts; pC->ReaderAudioAU.m_DTS = iCts; } /** * Update the audio begin cut offset */ pC->iAudioCtsOffset = iCts; } } /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_intPrepareAudioBeginCut(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intStepEncoding(M4MCS_InternalContext* pC, M4OSA_UInt8* pProgress) ****************************************************************************** */ static M4OSA_ERR M4MCS_intStepEncoding( M4MCS_InternalContext *pC, M4OSA_UInt8 *pProgress ) { M4OSA_ERR err; M4OSA_UInt32 uiAudioStepCount = 0; /* ---------- VIDEO TRANSCODING ---------- */ if( ( pC->novideo == M4OSA_FALSE) && (M4MCS_kStreamState_STARTED == pC->VideoState) ) /**< If the video encoding is going on */ { if( pC->EncodingVideoFormat == M4ENCODER_kNULL ) { err = M4MCS_intVideoNullEncoding(pC); } else { err = M4MCS_intVideoTranscoding(pC); } /** * No more space, quit properly */ if( M4WAR_WRITER_STOP_REQ == err ) { *pProgress = (M4OSA_UInt8)(( ( (M4OSA_UInt32)pC->dViDecCurrentCts - pC->uiBeginCutTime) * 100) / (pC->uiEndCutTime - pC->uiBeginCutTime)); pC->State = M4MCS_kState_FINISHED; /* bad file produced on very short 3gp file */ if( pC->dViDecCurrentCts - pC->uiBeginCutTime == 0 ) { /* Nothing has been encoded -> bad produced file -> error returned */ M4OSA_TRACE2_0( "M4MCS_intStepEncoding(): video transcoding returns\ M4MCS_ERR_OUTPUT_FILE_SIZE_TOO_SMALL"); return M4MCS_ERR_OUTPUT_FILE_SIZE_TOO_SMALL; } else { #ifndef M4MCS_AUDIOONLY /* clean AIR context needed to keep media aspect ratio*/ if( M4OSA_NULL != pC->m_air_context ) { err = M4AIR_cleanUp(pC->m_air_context); if( err != M4NO_ERROR ) { M4OSA_TRACE1_1( "M4xVSS_PictureCallbackFct: Error when cleaning AIR: 0x%x", err); return err; } pC->m_air_context = M4OSA_NULL; } #endif /*M4MCS_AUDIOONLY*/ M4OSA_TRACE2_0( "M4MCS_intStepEncoding(): video transcoding returns M4MCS_ERR_NOMORE_SPACE"); return M4MCS_ERR_NOMORE_SPACE; } } /**< The input plane is null because the input image will be obtained by the VPP filter from the context */ if( ( M4NO_ERROR != err) && (M4WAR_NO_MORE_AU != err) ) { M4OSA_TRACE1_1( "M4MCS_intStepEncoding(): video transcoding returns 0x%x!", err); return err; } } /* ---------- AUDIO TRANSCODING ---------- */ if( ( pC->noaudio == M4OSA_FALSE) && (M4MCS_kStreamState_STARTED == pC->AudioState) ) /**< If there is an audio stream */ { while( /**< If the video encoding is running, encode audio until we reach video time */ ( ( pC->novideo == M4OSA_FALSE) && (M4MCS_kStreamState_STARTED == pC->VideoState) && (pC->ReaderAudioAU.m_CTS + pC->m_audioAUDuration < pC->ReaderVideoAU.m_CTS)) || /**< If the video encoding is not running, perform 1 step of audio encoding */ (( M4MCS_kStreamState_STARTED == pC->AudioState) && (uiAudioStepCount < 1)) ) { uiAudioStepCount++; /**< check if an adio effect has to be applied*/ err = M4MCS_intCheckAudioEffects(pC); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intStepEncoding(): M4MCS_intCheckAudioEffects returns err: 0x%x", err); return err; } if( pC->AudioEncParams.Format == M4ENCODER_kAudioNULL ) { err = M4MCS_intAudioNullEncoding(pC); } else /**< Audio transcoding */ { err = M4MCS_intAudioTranscoding(pC); } /** * No more space, quit properly */ if( M4WAR_WRITER_STOP_REQ == err ) { *pProgress = (M4OSA_UInt8)(( ( (M4OSA_UInt32)pC->ReaderAudioAU.m_CTS - pC->uiBeginCutTime) * 100) / (pC->uiEndCutTime - pC->uiBeginCutTime)); pC->State = M4MCS_kState_FINISHED; /* bad file produced on very short 3gp file */ if( pC->ReaderAudioAU.m_CTS - pC->uiBeginCutTime == 0 ) { /* Nothing has been encoded -> bad produced file -> error returned */ M4OSA_TRACE2_0( "M4MCS_intStepEncoding():\ audio transcoding returns M4MCS_ERR_OUTPUT_FILE_SIZE_TOO_SMALL"); return M4MCS_ERR_OUTPUT_FILE_SIZE_TOO_SMALL; } else { #ifndef M4MCS_AUDIOONLY /* clean AIR context needed to keep media aspect ratio*/ if( M4OSA_NULL != pC->m_air_context ) { err = M4AIR_cleanUp(pC->m_air_context); if( err != M4NO_ERROR ) { M4OSA_TRACE1_1( "M4xVSS_PictureCallbackFct: Error when cleaning AIR: 0x%x", err); return err; } pC->m_air_context = M4OSA_NULL; } #endif /*M4MCS_AUDIOONLY*/ M4OSA_TRACE2_0( "M4MCS_intStepEncoding(): \ audio transcoding returns M4MCS_ERR_NOMORE_SPACE"); return M4MCS_ERR_NOMORE_SPACE; } } if( M4WAR_NO_MORE_AU == err ) { pC->AudioState = M4MCS_kStreamState_FINISHED; M4OSA_TRACE3_0( "M4MCS_intStepEncoding(): audio transcoding returns M4WAR_NO_MORE_AU"); break; } else if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intStepEncoding(): audio transcoding returns 0x%x", err); return err; } /** * Check for end cut */ /* We absolutely want to have less or same audio duration as video -> (2*pC->m_audioAUDuration) */ if( (M4OSA_UInt32)pC->ReaderAudioAU.m_CTS + (2 *pC->m_audioAUDuration) > pC->uiEndCutTime ) { pC->AudioState = M4MCS_kStreamState_FINISHED; break; } } } /* ---------- PROGRESS MANAGEMENT ---------- */ /** * Compute progress */ if( pC->novideo ) { if( pC->ReaderAudioAU.m_CTS < pC->uiBeginCutTime ) { *pProgress = 0; } else { *pProgress = (M4OSA_UInt8)(( ( (M4OSA_UInt32)pC->ReaderAudioAU.m_CTS - pC->uiBeginCutTime) * 100) / (pC->uiEndCutTime - pC->uiBeginCutTime)); } //printf(": %6.0f\b\b\b\b\b\b\b\b", pC->ReaderAudioAU.m_CTS); } else { if( pC->dViDecCurrentCts < pC->uiBeginCutTime ) { *pProgress = 0; } else { *pProgress = (M4OSA_UInt8)(( ( (M4OSA_UInt32)pC->dViDecCurrentCts - pC->uiBeginCutTime) * 100) / (pC->uiEndCutTime - pC->uiBeginCutTime)); } //printf(": %6.0f\b\b\b\b\b\b\b\b", pC->dViDecCurrentCts); } /** * Sanity check */ if( *pProgress > 99 ) { *pProgress = 99; } /** * Increment CTS for next step */ if( pC->novideo == M4OSA_FALSE ) { if( pC->EncodingVideoFormat == M4ENCODER_kNULL ) { pC->dViDecCurrentCts += 1; } else { pC->dViDecCurrentCts += pC->dCtsIncrement; } } /** * The transcoding is finished when no stream is being encoded anymore */ if( ( ( pC->novideo) || (M4MCS_kStreamState_FINISHED == pC->VideoState)) && (( pC->noaudio) || (M4MCS_kStreamState_FINISHED == pC->AudioState)) ) { /* the AIR part can only be used when video codecs are compiled*/ #ifndef M4MCS_AUDIOONLY /* clean AIR context needed to keep media aspect ratio*/ if( M4OSA_NULL != pC->m_air_context ) { err = M4AIR_cleanUp(pC->m_air_context); if( err != M4NO_ERROR ) { M4OSA_TRACE1_1( "M4xVSS_PictureCallbackFct: Error when cleaning AIR: 0x%x", err); return err; } pC->m_air_context = M4OSA_NULL; } #endif /*M4MCS_AUDIOONLY*/ /**/ *pProgress = 100; pC->State = M4MCS_kState_FINISHED; M4OSA_TRACE2_0( "M4MCS_intStepEncoding(): transcoding finished, returning M4MCS_WAR_TRANSCODING_DONE"); return M4MCS_WAR_TRANSCODING_DONE; } /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_intStepEncoding(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intStepBeginVideoJump(M4MCS_InternalContext* pC) ****************************************************************************** */ static M4OSA_ERR M4MCS_intStepBeginVideoJump( M4MCS_InternalContext *pC ) { M4OSA_ERR err; M4OSA_Int32 iCts; if( pC->novideo ) { pC->State = M4MCS_kState_BEGINVIDEODECODE; return M4NO_ERROR; } /** * Jump to the previous RAP in the clip (first get the time, then jump) */ iCts = (M4OSA_Int32)pC->dViDecStartingCts; err = pC->m_pReader->m_pFctGetPrevRapTime(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream, &iCts); if( M4WAR_READER_INFORMATION_NOT_PRESENT == err ) { /* No RAP table, jump backward and predecode */ iCts = (M4OSA_Int32)pC->dViDecStartingCts - M4MCS_NO_STSS_JUMP_POINT; if( iCts < 0 ) iCts = 0; } else if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intStepBeginVideoJump: m_pFctGetPrevRapTime returns 0x%x!", err); return err; } /* + CRLV6775 -H.264 Trimming */ if( M4OSA_TRUE == pC->bH264Trim ) { // Save jump time for safety, this fix should be generic M4OSA_Int32 iCtsOri = iCts; err = pC->m_pReader->m_pFctJump(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream, &iCts); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intStepBeginVideoJump: m_pFctJump(V) returns 0x%x!", err); return err; } if( pC->ReaderVideoAU1.m_structSize == 0 ) { /** * Initializes an access Unit */ err = pC->m_pReader->m_pFctFillAuStruct(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream, &pC->ReaderVideoAU1); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_open(): m_pReader->m_pFctFillAuStruct(video) returns 0x%x", err); return err; } err = pC->m_pReaderDataIt->m_pFctGetNextAu(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream, &pC->ReaderVideoAU1); if( M4WAR_NO_MORE_AU == err ) { M4OSA_TRACE2_0( "M4MCS_intVideoNullEncoding(): \ m_pReaderDataIt->m_pFctGetNextAu(video) returns M4WAR_NO_MORE_AU"); /* The audio transcoding is finished */ pC->VideoState = M4MCS_kStreamState_FINISHED; return err; } else if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intVideoNullEncoding():\ m_pReaderDataIt->m_pFctGetNextAu(video) returns 0x%x", err); return err; } pC->ReaderVideoAU1.m_structSize = 0; } err = H264MCS_ProcessSPS_PPS(pC->m_pInstance, (M4OSA_UInt8 *)pC->ReaderVideoAU1.m_dataAddress, pC->ReaderVideoAU1.m_size); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intStepBeginVideoJump: H264MCS_ProcessSPS_PPS returns 0x%x!", err); return err; } // Restore jump time for safety, this fix should be generic iCts = iCtsOri; } /* - CRLV6775 -H.264 Trimming */ /** * Decode one step */ pC->dViDecCurrentCts = (M4OSA_Double)(iCts + pC->iVideoBeginDecIncr); /** * Be sure we don't decode too far */ if( pC->dViDecCurrentCts > pC->dViDecStartingCts ) { pC->dViDecCurrentCts = pC->dViDecStartingCts; } /** * Decode at least once with the bJump flag to true */ M4OSA_TRACE3_1( "M4VSS3GPP_intClipDecodeVideoUpToCts: Decoding upTo CTS %.3f", pC->dViDecCurrentCts); pC->isRenderDup = M4OSA_FALSE; err = pC->m_pVideoDecoder->m_pFctDecode(pC->pViDecCtxt, &pC->dViDecCurrentCts, M4OSA_TRUE, 0); if( ( M4NO_ERROR != err) && (M4WAR_NO_MORE_AU != err) && (err != M4WAR_VIDEORENDERER_NO_NEW_FRAME) ) { M4OSA_TRACE1_1( "M4MCS_intStepBeginVideoJump: m_pFctDecode returns 0x%x!", err); return err; } if( err == M4WAR_VIDEORENDERER_NO_NEW_FRAME ) { M4OSA_TRACE2_0("Decoding output the same frame as before 1"); pC->isRenderDup = M4OSA_TRUE; } /** * Increment decoding cts for the next step */ pC->dViDecCurrentCts += (M4OSA_Double)pC->iVideoBeginDecIncr; /** * Update state automaton */ if( pC->dViDecCurrentCts > pC->dViDecStartingCts ) { /** * Be sure we don't decode too far */ pC->dViDecCurrentCts = pC->dViDecStartingCts; pC->State = M4MCS_kState_PROCESSING; } else { pC->State = M4MCS_kState_BEGINVIDEODECODE; } /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_intStepBeginVideoJump(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intStepBeginVideoDecode(M4MCS_InternalContext* pC) ****************************************************************************** */ static M4OSA_ERR M4MCS_intStepBeginVideoDecode( M4MCS_InternalContext *pC ) { M4OSA_ERR err; M4_MediaTime dDecTarget; if( pC->novideo ) { pC->State = M4MCS_kState_PROCESSING; return M4NO_ERROR; } /** * Decode */ dDecTarget = pC->dViDecCurrentCts; M4OSA_TRACE3_1("M4MCS_intStepBeginDecode: Decoding upTo CTS %.3f", pC->dViDecCurrentCts); pC->isRenderDup = M4OSA_FALSE; err = pC->m_pVideoDecoder->m_pFctDecode(pC->pViDecCtxt, &dDecTarget, M4OSA_FALSE, 0); if( ( M4NO_ERROR != err) && (M4WAR_NO_MORE_AU != err) && (err != M4WAR_VIDEORENDERER_NO_NEW_FRAME) ) { M4OSA_TRACE1_1( "M4MCS_intStepBeginVideoDecode: m_pFctDecode returns 0x%x!", err); return err; } if( err == M4WAR_VIDEORENDERER_NO_NEW_FRAME ) { M4OSA_TRACE2_0("Decoding output the same frame as before 2"); pC->isRenderDup = M4OSA_TRUE; } /** * Increment decoding cts for the next step */ pC->dViDecCurrentCts += (M4OSA_Double)pC->iVideoBeginDecIncr; /** * Update state automaton, if needed */ if( ( (M4OSA_UInt32)pC->dViDecCurrentCts > pC->dViDecStartingCts) || (M4WAR_NO_MORE_AU == err) ) { /** * Be sure we don't decode too far */ pC->dViDecCurrentCts = (M4OSA_Double)pC->dViDecStartingCts; pC->State = M4MCS_kState_PROCESSING; } /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_intStepBeginVideoDecode(): returning M4NO_ERROR"); return M4NO_ERROR; } /*****************************/ /* define AMR silence frames */ /*****************************/ #define M4VSS3GPP_AMR_AU_SILENCE_FRAME_048_SIZE 13 #define M4VSS3GPP_AMR_AU_SILENCE_FRAME_048_DURATION 160 #ifdef M4VSS3GPP_SILENCE_FRAMES const M4OSA_UInt8 M4VSS3GPP_AMR_AU_SILENCE_FRAME_048[ M4VSS3GPP_AMR_AU_SILENCE_FRAME_048_SIZE] = { 0x04, 0xFF, 0x18, 0xC7, 0xF0, 0x0D, 0x04, 0x33, 0xFF, 0xE0, 0x00, 0x00, 0x00 }; #else extern const M4OSA_UInt8 M4VSS3GPP_AMR_AU_SILENCE_FRAME_048[M4VSS3GPP_AMR_AU_SILENCE_FRAME_048_SIZE]; #endif /*****************************/ /* define AAC silence frames */ /*****************************/ #define M4VSS3GPP_AAC_AU_SILENCE_MONO_SIZE 4 #ifdef M4VSS3GPP_SILENCE_FRAMES const M4OSA_UInt8 M4VSS3GPP_AAC_AU_SILENCE_MONO[ M4VSS3GPP_AAC_AU_SILENCE_MONO_SIZE] = { 0x00, 0xC8, 0x20, 0x07 }; #else extern const M4OSA_UInt8 M4VSS3GPP_AAC_AU_SILENCE_MONO[M4VSS3GPP_AAC_AU_SILENCE_MONO_SIZE]; #endif #define M4VSS3GPP_AAC_AU_SILENCE_STEREO_SIZE 6 #ifdef M4VSS3GPP_SILENCE_FRAMES const M4OSA_UInt8 M4VSS3GPP_AAC_AU_SILENCE_STEREO[ M4VSS3GPP_AAC_AU_SILENCE_STEREO_SIZE] = { 0x21, 0x10, 0x03, 0x20, 0x54, 0x1C }; #else extern const M4OSA_UInt8 M4VSS3GPP_AAC_AU_SILENCE_STEREO[M4VSS3GPP_AAC_AU_SILENCE_STEREO_SIZE]; #endif /** ****************************************************************************** * M4OSA_ERR M4MCS_intAudioNullEncoding(M4MCS_InternalContext* pC) * @return M4NO_ERROR: No error ****************************************************************************** */ static M4OSA_ERR M4MCS_intAudioNullEncoding( M4MCS_InternalContext *pC ) { M4OSA_ERR err; if( pC->noaudio ) return M4NO_ERROR; /* Check if all audio frame has been written (happens at begin cut) */ if( pC->ReaderAudioAU.m_size == 0 ) { /** * Initializes a new AU if needed */ if( pC->ReaderAudioAU1.m_structSize == 0 ) { /** * Initializes an access Unit */ err = pC->m_pReader->m_pFctFillAuStruct(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderAudioStream, &pC->ReaderAudioAU1); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_open(): m_pReader->m_pFctFillAuStruct(audio) returns 0x%x", err); return err; } pC->m_pDataAddress1 = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(pC->ReaderAudioAU1.m_maxsize, M4MCS, (M4OSA_Char *)"Temporary AU1 buffer"); if( pC->m_pDataAddress1 == M4OSA_NULL ) { M4OSA_TRACE1_0( "M4MCS_intAudioNullEncoding(): allocation error"); return M4ERR_ALLOC; } err = pC->m_pReaderDataIt->m_pFctGetNextAu(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderAudioStream, &pC->ReaderAudioAU1); if( M4WAR_NO_MORE_AU == err ) { M4OSA_TRACE2_0( "M4MCS_intAudioNullEncoding():\ m_pReaderDataIt->m_pFctGetNextAu(audio) returns M4WAR_NO_MORE_AU"); /* The audio transcoding is finished */ pC->AudioState = M4MCS_kStreamState_FINISHED; return err; } else if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intAudioNullEncoding(): \ m_pReaderDataIt->m_pFctGetNextAu(Audio) returns 0x%x", err); return err; } /*FB 2009.04.02: PR surnxp#616: Crash in MCS while Audio AU copying , constant memory reader case*/ if( pC->ReaderAudioAU1.m_maxsize > pC->pReaderAudioStream->m_basicProperties.m_maxAUSize ) { /* Constant memory reader case, we need to reallocate the temporary buffers */ M4MCS_intReallocTemporaryAU((M4OSA_MemAddr8 *) &(pC->m_pDataAddress1), pC->ReaderAudioAU1.m_maxsize); /* pC->m_pDataAddress1 and pC->m_pDataAddress2 must be reallocated at the same time */ /* because pC->pReaderAudioStream->m_basicProperties.m_maxAUSize take maximum value. Then the test "if(pC->ReaderAudioAU?.m_maxsize > pC->pReaderAudioStream->m_basicProperties.m_maxAUSize)" is never true */ /* and the size of the second buffer is never changed. */ M4MCS_intReallocTemporaryAU((M4OSA_MemAddr8 *) &(pC->m_pDataAddress2), pC->ReaderAudioAU1.m_maxsize); /* pC->m_pDataAddress1 and pC->m_pDataAddress2 must be reallocated at the same time */ /* Update stream properties */ pC->pReaderAudioStream->m_basicProperties.m_maxAUSize = pC->ReaderAudioAU1.m_maxsize; } /**/ memcpy((void *)pC->m_pDataAddress1, (void *)pC->ReaderAudioAU1.m_dataAddress, pC->ReaderAudioAU1.m_size); } if( pC->ReaderAudioAU2.m_structSize == 0 ) { /** * Initializes an access Unit */ err = pC->m_pReader->m_pFctFillAuStruct(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderAudioStream, &pC->ReaderAudioAU2); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_open(): m_pReader->m_pFctFillAuStruct(audio) returns 0x%x", err); return err; } pC->m_pDataAddress2 = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(pC->ReaderAudioAU2.m_maxsize, M4MCS, (M4OSA_Char *)"Temporary AU buffer"); if( pC->m_pDataAddress2 == M4OSA_NULL ) { M4OSA_TRACE1_0( "M4MCS_intAudioNullEncoding(): allocation error"); return M4ERR_ALLOC; } } /** * Read the next audio AU in the input file */ if( pC->ReaderAudioAU2.m_CTS > pC->ReaderAudioAU1.m_CTS ) { memcpy((void *) &pC->ReaderAudioAU, (void *) &pC->ReaderAudioAU2, sizeof(M4_AccessUnit)); err = pC->m_pReaderDataIt->m_pFctGetNextAu(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderAudioStream, &pC->ReaderAudioAU1); if( pC->ReaderAudioAU1.m_maxsize > pC->pReaderAudioStream->m_basicProperties.m_maxAUSize ) { /* Constant memory reader case, we need to reallocate the temporary buffers */ M4MCS_intReallocTemporaryAU((M4OSA_MemAddr8 *) &(pC->m_pDataAddress1), pC->ReaderAudioAU1.m_maxsize); /* pC->m_pDataAddress1 * and pC->m_pDataAddress2 must be reallocated at the same time * * because pC->pReaderAudioStream->m_basicProperties.m_maxAUSize take * maximum value. Then the test "if(pC->ReaderAudioAU?.m_maxsize > * pC->pReaderAudioStream->m_basicProperties.m_maxAUSize)" is never true * * and the size of the second buffer is never changed. */ M4MCS_intReallocTemporaryAU((M4OSA_MemAddr8 *) &(pC->m_pDataAddress2), pC->ReaderAudioAU1.m_maxsize); /* pC->m_pDataAddress1 and * pC->m_pDataAddress2 must be reallocated at the same time * Update stream properties */ pC->pReaderAudioStream->m_basicProperties.m_maxAUSize = pC->ReaderAudioAU1.m_maxsize; } /**/ memcpy((void *)pC->m_pDataAddress1, (void *)pC->ReaderAudioAU1.m_dataAddress, pC->ReaderAudioAU1.m_size); pC->m_audioAUDuration = pC->ReaderAudioAU1.m_CTS - pC->ReaderAudioAU2.m_CTS; pC->ReaderAudioAU.m_dataAddress = pC->m_pDataAddress2; } else { memcpy((void *) &pC->ReaderAudioAU, (void *) &pC->ReaderAudioAU1, sizeof(M4_AccessUnit)); err = pC->m_pReaderDataIt->m_pFctGetNextAu(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderAudioStream, &pC->ReaderAudioAU2); /* Crash in MCS while Audio AU copying , * constant memory reader case */ if( pC->ReaderAudioAU2.m_maxsize > pC->pReaderAudioStream->m_basicProperties.m_maxAUSize ) { /* Constant memory reader case, we need to reallocate the temporary buffers */ M4MCS_intReallocTemporaryAU((M4OSA_MemAddr8 *) &(pC->m_pDataAddress2), pC->ReaderAudioAU2.m_maxsize); /* pC->m_pDataAddress1 and * pC->m_pDataAddress2 must be reallocated at the same time * because pC->pReaderAudioStream->m_basicProperties.m_maxAUSize take maximum * value. Then the test "if(pC->ReaderAudioAU?.m_maxsize > pC->pReaderAudioStream-> * m_basicProperties.m_maxAUSize)" is never true * and the size of the second buffer is never changed. */ M4MCS_intReallocTemporaryAU((M4OSA_MemAddr8 *) &(pC->m_pDataAddress1), pC->ReaderAudioAU2.m_maxsize); /* [ END ] 20091008 JFV PR fix surnxpsw#1071: pC->m_pDataAddress1 and pC->m_pDataAddress2 must be reallocated at the same time */ /* Update stream properties */ pC->pReaderAudioStream->m_basicProperties.m_maxAUSize = pC->ReaderAudioAU2.m_maxsize; } /**/ memcpy((void *)pC->m_pDataAddress2, (void *)pC->ReaderAudioAU2.m_dataAddress, pC->ReaderAudioAU2.m_size); pC->m_audioAUDuration = pC->ReaderAudioAU2.m_CTS - pC->ReaderAudioAU1.m_CTS; pC->ReaderAudioAU.m_dataAddress = pC->m_pDataAddress1; } if( M4WAR_NO_MORE_AU == err ) { M4OSA_TRACE2_0( "M4MCS_intAudioNullEncoding(): \ m_pReaderDataIt->m_pFctGetNextAu(audio) returns M4WAR_NO_MORE_AU"); /* The audio transcoding is finished */ pC->AudioState = M4MCS_kStreamState_FINISHED; return err; } else if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intAudioNullEncoding(): \ m_pReaderDataIt->m_pFctGetNextAu(Audio) returns 0x%x", err); return err; } } /** * Prepare the writer AU */ err = pC->pWriterDataFcts->pStartAU(pC->pWriterContext, M4MCS_WRITER_AUDIO_STREAM_ID, &pC->WriterAudioAU); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intAudioNullEncoding(): pWriterDataFcts->pStartAU(Audio) returns 0x%x", err); return err; } if( pC->uiAudioAUCount == 0 ) /* If it is the first AU, we set it to silence (else, errors 0x3841, 0x3847 in our AAC decoder) */ { if( pC->InputFileProperties.AudioStreamType == M4VIDEOEDITING_kAAC || pC->InputFileProperties.AudioStreamType == M4VIDEOEDITING_kAACplus || pC->InputFileProperties.AudioStreamType == M4VIDEOEDITING_keAACplus ) { if( pC->InputFileProperties.uiNbChannels == 1 ) { pC->WriterAudioAU.size = M4VSS3GPP_AAC_AU_SILENCE_MONO_SIZE; memcpy((void *)pC->WriterAudioAU.dataAddress, (void *)M4VSS3GPP_AAC_AU_SILENCE_MONO, pC->WriterAudioAU.size); } else if( pC->InputFileProperties.uiNbChannels == 2 ) { pC->WriterAudioAU.size = M4VSS3GPP_AAC_AU_SILENCE_STEREO_SIZE; memcpy((void *)pC->WriterAudioAU.dataAddress, (void *)M4VSS3GPP_AAC_AU_SILENCE_STEREO, pC->WriterAudioAU.size); } else { /* Must never happen ...*/ M4OSA_TRACE1_0( "M4MCS_intAudioNullEncoding: Bad number of channels in audio input"); return M4MCS_ERR_INVALID_INPUT_FILE; } } else if( pC->InputFileProperties.AudioStreamType == M4VIDEOEDITING_kAMR_NB ) { pC->WriterAudioAU.size = M4VSS3GPP_AMR_AU_SILENCE_FRAME_048_SIZE; memcpy((void *)pC->WriterAudioAU.dataAddress, (void *)M4VSS3GPP_AMR_AU_SILENCE_FRAME_048, pC->WriterAudioAU.size); /* Some remaining AMR AU needs to be copied */ if( pC->ReaderAudioAU.m_size != 0 ) { /* Update Writer AU */ pC->WriterAudioAU.size += pC->ReaderAudioAU.m_size; memcpy((void *)(pC->WriterAudioAU.dataAddress + M4VSS3GPP_AMR_AU_SILENCE_FRAME_048_SIZE), (void *)pC->ReaderAudioAU.m_dataAddress, pC->ReaderAudioAU.m_size); } } else { /*MP3 case: copy the AU*/ M4OSA_TRACE3_1( "M4MCS_intAudioNullEncoding(): Copying audio AU: size=%d", pC->ReaderAudioAU.m_size); memcpy((void *)pC->WriterAudioAU.dataAddress, (void *)pC->ReaderAudioAU.m_dataAddress, pC->ReaderAudioAU.m_size); pC->WriterAudioAU.size = pC->ReaderAudioAU.m_size; } } else { /** * Copy audio data from reader AU to writer AU */ M4OSA_TRACE3_1( "M4MCS_intAudioNullEncoding(): Copying audio AU: size=%d", pC->ReaderAudioAU.m_size); memcpy((void *)pC->WriterAudioAU.dataAddress, (void *)pC->ReaderAudioAU.m_dataAddress, pC->ReaderAudioAU.m_size); pC->WriterAudioAU.size = pC->ReaderAudioAU.m_size; } /** * Convert CTS unit from milliseconds to timescale */ pC->WriterAudioAU.CTS = (M4OSA_Time)((( pC->ReaderAudioAU.m_CTS - pC->iAudioCtsOffset) * (pC->WriterAudioStream.timeScale / 1000.0))); if( pC->InputFileProperties.AudioStreamType == M4VIDEOEDITING_kAMR_NB && pC->uiAudioAUCount == 0 ) { pC->iAudioCtsOffset -= 20; /* Duration of a silence AMR AU, to handle the duration of the added silence frame */ } pC->WriterAudioAU.nbFrag = 0; M4OSA_TRACE3_1("M4MCS_intAudioNullEncoding(): audio AU: CTS=%d ms", pC->WriterAudioAU.CTS); /** * Write it to the output file */ pC->uiAudioAUCount++; err = pC->pWriterDataFcts->pProcessAU(pC->pWriterContext, M4MCS_WRITER_AUDIO_STREAM_ID, &pC->WriterAudioAU); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intAudioNullEncoding(): pWriterDataFcts->pProcessAU(Audio) returns 0x%x", err); return err; } /* All the audio has been written */ pC->ReaderAudioAU.m_size = 0; /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_intAudioNullEncoding(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * @brief Init Audio Transcoding * @return M4NO_ERROR: No error ****************************************************************************** */ static M4OSA_ERR M4MCS_intAudioTranscoding( M4MCS_InternalContext *pC ) { M4OSA_ERR err; /**< General error */ M4OSA_UInt32 uiBytesDec; /**< Nb of bytes available in the decoder OUT buffer */ M4OSA_UInt32 uiDecoder2Ssrc_NbBytes; /**< Nb of bytes copied into the ssrc IN buffer */ int ssrcErr; /**< Error while ssrc processing */ M4OSA_UInt32 uiSsrcInSize; /**< Size in bytes of ssrc intput buffer */ M4OSA_UInt32 uiSsrcInRoom; /**< Nb of bytes available in the ssrc IN buffer */ M4OSA_MemAddr8 pSsrcInput; /**< Pointer to the good buffer location for ssrc input */ M4OSA_UInt32 uiSsrcOutSize; /**< Size in bytes of ssrc output buffer */ M4OSA_UInt32 uiBytesSsrc; /**< Nb of bytes available in the ssrc OUT buffer */ M4OSA_UInt8 needChannelConversion; /**< Flag to indicate if a stereo <-> mono conversion is needed */ M4OSA_UInt32 uiChannelConvertorCoeff; /**< Multiplicative coefficient if stereo <-> mono conversion is applied */ M4OSA_MemAddr8 pChannelConvertorInput = M4OSA_NULL; /**< Pointer to the good buffer location for channel convertor input */ M4OSA_UInt32 uiChannelConvertorNbSamples = 0; /**< Nb of pcm samples to convert in channel convertor */ M4OSA_MemAddr8 pChannelConvertorOutput = M4OSA_NULL; /**< Pointer to the good buffer location for channel convertor output */ M4OSA_Time frameTimeDelta; /**< Duration of the encoded (then written) data */ M4OSA_UInt32 uiEncoderInRoom; /**< Nb of bytes available in the encoder IN buffer */ M4OSA_UInt32 uiSsrc2Encoder_NbBytes; /**< Nb of bytes copied from the ssrc OUT buffer */ M4OSA_MemAddr8 pEncoderInput; /**< Pointer to the good buffer location for encoder input */ M4ENCODER_AudioBuffer pEncInBuffer; /**< Encoder input buffer for api */ M4ENCODER_AudioBuffer pEncOutBuffer; /**< Encoder output buffer for api */ M4OSA_Int16 *tempBuffOut = M4OSA_NULL; /*FlB 2009.03.04: apply audio effects if an effect is active*/ M4OSA_Int8 *pActiveEffectNumber = &(pC->pActiveEffectNumber); uint32_t errCode = M4NO_ERROR; if( pC->noaudio ) return M4NO_ERROR; /* _________________ */ /*| |*/ /*| READ AND DECODE |*/ /*|_________________|*/ /* Check if we have to empty the decoder out buffer first */ if( M4OSA_NULL != pC->pPosInDecBufferOut ) { goto m4mcs_intaudiotranscoding_feed_resampler; } err = pC->m_pAudioDecoder->m_pFctStepAudioDec(pC->pAudioDecCtxt, M4OSA_NULL, &pC->AudioDecBufferOut, M4OSA_FALSE); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intAudioTranscoding(): m_pAudioDecoder->m_pFctStepAudio returns 0x%x", err); return err; } #ifdef MCS_DUMP_PCM_TO_FILE fwrite(pC->AudioDecBufferOut.m_dataAddress, pC->AudioDecBufferOut.m_bufferSize, 1, file_pcm_decoder); #endif pC->m_pAudioDecoder->m_pFctGetOptionAudioDec(pC->pAudioDecCtxt, M4AD_kOptionID_GetAudioAUErrCode, (M4OSA_DataOption) &errCode); if ( M4WAR_NO_MORE_AU == errCode ) { pC->AudioState = M4MCS_kStreamState_FINISHED; M4OSA_TRACE2_0( "M4MCS_intAudioTranscoding():\ m_pReaderDataIt->m_pFctGetNextAu(audio) returns M4WAR_NO_MORE_AU"); return errCode; } /* Set the current position in the decoder out buffer */ pC->pPosInDecBufferOut = pC->AudioDecBufferOut.m_dataAddress; /* ________________ */ /*| |*/ /*| FEED RESAMPLER |*/ /*|________________|*/ m4mcs_intaudiotranscoding_feed_resampler: /* Check if we have to empty the ssrc out buffer first */ if( M4OSA_NULL != pC->pPosInSsrcBufferOut ) { goto m4mcs_intaudiotranscoding_prepare_input_buffer; } /* Compute number of bytes remaining in the decoder buffer */ uiSsrcInSize = pC->iSsrcNbSamplIn * sizeof(short) * pC->pReaderAudioStream->m_nbChannels; uiBytesDec = ( pC->AudioDecBufferOut.m_dataAddress + pC->AudioDecBufferOut.m_bufferSize) - pC->pPosInDecBufferOut; /* Check if we can feed directly the Ssrc with the decoder out buffer */ if( ( pC->pPosInSsrcBufferIn == pC->pSsrcBufferIn) && (uiBytesDec >= uiSsrcInSize) ) { pSsrcInput = pC->pPosInDecBufferOut; /* update data consumed into decoder buffer after resampling */ if( uiBytesDec == uiSsrcInSize ) pC->pPosInDecBufferOut = M4OSA_NULL; else pC->pPosInDecBufferOut += uiSsrcInSize; goto m4mcs_intaudiotranscoding_do_resampling; } /** * Compute remaining space in Ssrc buffer in */ uiSsrcInRoom = ( pC->pSsrcBufferIn + uiSsrcInSize) - pC->pPosInSsrcBufferIn; /** * Nb of bytes copied is the minimum between nb of bytes remaining in * decoder out buffer and space remaining in ssrc in buffer */ uiDecoder2Ssrc_NbBytes = (uiSsrcInRoom < uiBytesDec) ? uiSsrcInRoom : uiBytesDec; /** * Copy from the decoder out buffer into the Ssrc in buffer */ memcpy((void *)pC->pPosInSsrcBufferIn, (void *)pC->pPosInDecBufferOut, uiDecoder2Ssrc_NbBytes); /** * Update the position in the decoder out buffer */ pC->pPosInDecBufferOut += uiDecoder2Ssrc_NbBytes; /** * Update the position in the Ssrc in buffer */ pC->pPosInSsrcBufferIn += uiDecoder2Ssrc_NbBytes; /** * Check if the decoder buffer out is empty */ if( ( pC->pPosInDecBufferOut - pC->AudioDecBufferOut.m_dataAddress) == (M4OSA_Int32)pC->AudioDecBufferOut.m_bufferSize ) { pC->pPosInDecBufferOut = M4OSA_NULL; } /* Check if the Ssrc in buffer is ready (= full) */ if( ( pC->pPosInSsrcBufferIn - pC->pSsrcBufferIn) < (M4OSA_Int32)uiSsrcInSize ) { goto m4mcs_intaudiotranscoding_end; } pSsrcInput = pC->pSsrcBufferIn; /* update data consumed into ssrc buffer in after resampling (empty) */ pC->pPosInSsrcBufferIn = pC->pSsrcBufferIn; /* ___________________ */ /*| |*/ /*| DO THE RESAMPLING |*/ /*|___________________|*/ m4mcs_intaudiotranscoding_do_resampling: /** * No need for memcopy, we can feed Ssrc directly with the data in the audio decoder out buffer*/ ssrcErr = 0; if( pC->pReaderAudioStream->m_nbChannels == 1 ) { tempBuffOut = (short *)M4OSA_32bitAlignedMalloc((pC->iSsrcNbSamplOut * sizeof(short) * 2 * ((*pC).InputFileProperties).uiNbChannels), M4VSS3GPP,(M4OSA_Char *) "tempBuffOut"); memset((void *)tempBuffOut, 0,(pC->iSsrcNbSamplOut * sizeof(short) * 2 * ((*pC).InputFileProperties).uiNbChannels)); LVAudioresample_LowQuality((short *)tempBuffOut, (short *)pSsrcInput, pC->iSsrcNbSamplOut, pC->pLVAudioResampler); } else { memset((void *)pC->pSsrcBufferOut, 0, (pC->iSsrcNbSamplOut * sizeof(short) * ((*pC).InputFileProperties).uiNbChannels)); LVAudioresample_LowQuality((short *)pC->pSsrcBufferOut, (short *)pSsrcInput, pC->iSsrcNbSamplOut, pC->pLVAudioResampler); } if( pC->pReaderAudioStream->m_nbChannels == 1 ) { From2iToMono_16((short *)tempBuffOut, (short *)pC->pSsrcBufferOut, (short)pC->iSsrcNbSamplOut); free(tempBuffOut); } if( 0 != ssrcErr ) { M4OSA_TRACE1_1( "M4MCS_intAudioTranscoding: SSRC_Process returns 0x%x, \ returning M4MCS_ERR_AUDIO_CONVERSION_FAILED", ssrcErr); return M4MCS_ERR_AUDIO_CONVERSION_FAILED; } pC->pPosInSsrcBufferOut = pC->pSsrcBufferOut; /* ______________________ */ /*| |*/ /*| PREPARE INPUT BUFFER |*/ /*|______________________|*/ m4mcs_intaudiotranscoding_prepare_input_buffer: /* Set the flag for channel conversion requirement */ if( ( pC->AudioEncParams.ChannelNum == M4ENCODER_kMono) && (pC->pReaderAudioStream->m_nbChannels == 2) ) { needChannelConversion = 1; uiChannelConvertorCoeff = 4; } else if( ( pC->AudioEncParams.ChannelNum == M4ENCODER_kStereo) && (pC->pReaderAudioStream->m_nbChannels == 1) ) { needChannelConversion = 2; uiChannelConvertorCoeff = 1; } else { needChannelConversion = 0; uiChannelConvertorCoeff = 2; } /* Compute number of bytes remaining in the Ssrc buffer */ uiSsrcOutSize = pC->iSsrcNbSamplOut * sizeof(short) * pC->pReaderAudioStream->m_nbChannels; uiBytesSsrc = ( pC->pSsrcBufferOut + uiSsrcOutSize) - pC->pPosInSsrcBufferOut; /* Check if the ssrc buffer is full */ if( pC->pPosInSsrcBufferOut == pC->pSsrcBufferOut ) { uiSsrc2Encoder_NbBytes = pC->audioEncoderGranularity * uiChannelConvertorCoeff / 2; /* Check if we can feed directly the encoder with the ssrc out buffer */ if( ( pC->pPosInAudioEncoderBuffer == M4OSA_NULL) && (uiBytesSsrc >= uiSsrc2Encoder_NbBytes) ) { /* update position in ssrc out buffer after encoding */ if( uiBytesSsrc == uiSsrc2Encoder_NbBytes ) pC->pPosInSsrcBufferOut = M4OSA_NULL; else pC->pPosInSsrcBufferOut += uiSsrc2Encoder_NbBytes; /* mark the encoder buffer ready (= full) */ pC->pPosInAudioEncoderBuffer = pC->pAudioEncoderBuffer + pC->audioEncoderGranularity; if( needChannelConversion > 0 ) { /* channel convertor writes directly into encoder buffer */ pEncoderInput = pC->pAudioEncoderBuffer; pChannelConvertorInput = pC->pSsrcBufferOut; pChannelConvertorOutput = pC->pAudioEncoderBuffer; uiChannelConvertorNbSamples = uiSsrc2Encoder_NbBytes / sizeof(short); goto m4mcs_intaudiotranscoding_channel_convertor; } else { /* encode directly from ssrc out buffer */ pEncoderInput = pC->pSsrcBufferOut; goto m4mcs_intaudiotranscoding_encode_and_write; } } } /** * Compute remaining space in encoder buffer in */ if( pC->pPosInAudioEncoderBuffer == M4OSA_NULL ) { pC->pPosInAudioEncoderBuffer = pC->pAudioEncoderBuffer; } uiEncoderInRoom = ( pC->pAudioEncoderBuffer + pC->audioEncoderGranularity) - pC->pPosInAudioEncoderBuffer; pEncoderInput = pC->pAudioEncoderBuffer; /** * Nb of bytes copied is the minimum between nb of bytes remaining in * decoder out buffer and space remaining in ssrc in buffer */ uiSsrc2Encoder_NbBytes = (( uiEncoderInRoom * uiChannelConvertorCoeff / 2) < uiBytesSsrc) ? (uiEncoderInRoom * uiChannelConvertorCoeff / 2) : uiBytesSsrc; if( needChannelConversion > 0 ) { /* channel convertor writes directly into encoder buffer */ pChannelConvertorInput = pC->pPosInSsrcBufferOut; pChannelConvertorOutput = pC->pPosInAudioEncoderBuffer; uiChannelConvertorNbSamples = uiSsrc2Encoder_NbBytes / sizeof(short); } else { /* copy from the ssrc out buffer into the encoder in buffer */ memcpy((void *)pC->pPosInAudioEncoderBuffer, (void *)pC->pPosInSsrcBufferOut, uiSsrc2Encoder_NbBytes); } /* Update position in ssrc out buffer after encoding */ pC->pPosInSsrcBufferOut += uiSsrc2Encoder_NbBytes; /* Update the position in the encoder in buffer */ pC->pPosInAudioEncoderBuffer += uiSsrc2Encoder_NbBytes * 2 / uiChannelConvertorCoeff; /* Check if the ssrc buffer out is empty */ if( ( pC->pPosInSsrcBufferOut - pC->pSsrcBufferOut) == (M4OSA_Int32)uiSsrcOutSize ) { pC->pPosInSsrcBufferOut = M4OSA_NULL; } /* go to next statement */ if( needChannelConversion > 0 ) goto m4mcs_intaudiotranscoding_channel_convertor; else goto m4mcs_intaudiotranscoding_encode_and_write; /* _________________ */ /*| |*/ /*| STEREO <-> MONO |*/ /*|_________________|*/ m4mcs_intaudiotranscoding_channel_convertor: /* convert the input pcm stream to mono or to stereo */ switch( needChannelConversion ) { case 1: /* stereo to mono */ From2iToMono_16((short *)pChannelConvertorInput, (short *)pChannelConvertorOutput, (short)(uiChannelConvertorNbSamples / 2)); break; case 2: /* mono to stereo */ MonoTo2I_16((short *)pChannelConvertorInput, (short *)pChannelConvertorOutput, (short)uiChannelConvertorNbSamples); break; } /* __________________ */ /*| |*/ /*| ENCODE AND WRITE |*/ /*|__________________|*/ m4mcs_intaudiotranscoding_encode_and_write: /* Check if the encoder in buffer is ready (= full) */ if( ( pC->pPosInAudioEncoderBuffer - pC->pAudioEncoderBuffer) < (M4OSA_Int32)pC->audioEncoderGranularity ) { goto m4mcs_intaudiotranscoding_end; } /* [Mono] or [Stereo interleaved] : all is in one buffer */ pEncInBuffer.pTableBuffer[0] = pEncoderInput; pEncInBuffer.pTableBufferSize[0] = pC->audioEncoderGranularity; pEncInBuffer.pTableBuffer[1] = M4OSA_NULL; pEncInBuffer.pTableBufferSize[1] = 0; /* Time in ms from data size, because it is PCM16 samples */ frameTimeDelta = ( pEncInBuffer.pTableBufferSize[0] * uiChannelConvertorCoeff / 2) / sizeof(short) / pC->pReaderAudioStream->m_nbChannels; /** * Prepare the writer AU */ err = pC->pWriterDataFcts->pStartAU(pC->pWriterContext, M4MCS_WRITER_AUDIO_STREAM_ID, &pC->WriterAudioAU); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intAudioTranscoding(): pWriterDataFcts->pStartAU(Audio) returns 0x%x", err); return err; } /*FlB 2009.03.04: apply audio effects if an effect is active*/ if( *pActiveEffectNumber >= 0 && *pActiveEffectNumber < pC->nbEffects ) { if( pC->pEffects[*pActiveEffectNumber].ExtAudioEffectFct != M4OSA_NULL ) { M4MCS_ExternalProgress pProgress; M4OSA_UInt32 tempProgress = 0; pProgress.uiClipTime = (M4OSA_UInt32)pC->ReaderAudioAU.m_CTS; pProgress.uiOutputTime = ( pC->WriterAudioAU.CTS * 1000) / pC->WriterAudioStream.timeScale; tempProgress = ( (M4OSA_UInt32)pC->ReaderAudioAU.m_CTS - pC->pEffects[*pActiveEffectNumber].uiStartTime - pC->uiBeginCutTime) * 1000; pProgress.uiProgress = (M4OSA_UInt32)(tempProgress / (M4OSA_UInt32)pC->pEffects[ *pActiveEffectNumber].uiDuration); err = pC->pEffects[*pActiveEffectNumber].ExtAudioEffectFct( pC->pEffects[*pActiveEffectNumber].pExtAudioEffectFctCtxt, (M4OSA_Int16 *)pEncInBuffer.pTableBuffer[0], pEncInBuffer.pTableBufferSize[0], &pProgress); if( err != M4NO_ERROR ) { M4OSA_TRACE1_1( "M4MCS_intAudioTranscoding(): ExtAudioEffectFct() returns 0x%x", err); return err; } } } /** * Prepare output buffer */ pEncOutBuffer.pTableBuffer[0] = (M4OSA_MemAddr8)pC->WriterAudioAU.dataAddress; pEncOutBuffer.pTableBufferSize[0] = 0; #ifdef MCS_DUMP_PCM_TO_FILE fwrite(pEncInBuffer.pTableBuffer[0], pEncInBuffer.pTableBufferSize[0], 1, file_pcm_encoder); #endif if( M4OSA_FALSE == pC->b_isRawWriter ) { /* This allow to write PCM data to file and to encode AMR data, when output file is not RAW */ if( pC->pOutputPCMfile != M4OSA_NULL ) { pC->pOsaFileWritPtr->writeData(pC->pOutputPCMfile, pEncInBuffer.pTableBuffer[0], pEncInBuffer.pTableBufferSize[0]); } /** * Encode the PCM audio */ err = pC->pAudioEncoderGlobalFcts->pFctStep(pC->pAudioEncCtxt, &pEncInBuffer, &pEncOutBuffer); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intAudioTranscoding(): pAudioEncoderGlobalFcts->pFctStep returns 0x%x", err); return err; } /* update data consumed into encoder buffer in after encoding (empty) */ pC->pPosInAudioEncoderBuffer = M4OSA_NULL; /** * Set AU cts and size */ pC->WriterAudioAU.size = pEncOutBuffer. pTableBufferSize[0]; /**< Get the size of encoded data */ pC->WriterAudioAU.CTS += frameTimeDelta; /** * Update duration of the encoded AU */ pC->m_audioAUDuration = ( frameTimeDelta * 1000) / pC->WriterAudioStream.timeScale; /** * Write the encoded AU to the output file */ pC->uiAudioAUCount++; err = pC->pWriterDataFcts->pProcessAU(pC->pWriterContext, M4MCS_WRITER_AUDIO_STREAM_ID, &pC->WriterAudioAU); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intAudioTranscoding(): pWriterDataFcts->pProcessAU(Audio) returns 0x%x", err); return err; } } else { /* update data consumed into encoder buffer in after encoding (empty) */ pC->pPosInAudioEncoderBuffer = M4OSA_NULL; pC->WriterAudioAU.dataAddress = (M4OSA_MemAddr32) pEncoderInput; /* will be converted back to u8* in file write */ pC->WriterAudioAU.size = pC->audioEncoderGranularity; pC->uiAudioAUCount++; err = pC->pWriterDataFcts->pProcessAU(pC->pWriterContext, M4MCS_WRITER_AUDIO_STREAM_ID, &pC->WriterAudioAU); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intAudioTranscoding(): pWriterDataFcts->pProcessAU(Audio) returns 0x%x", err); return err; } } /* _______________ */ /*| |*/ /*| ONE PASS DONE |*/ /*|_______________|*/ m4mcs_intaudiotranscoding_end: /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_intAudioTranscoding(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intReallocTemporaryAU(M4OSA_MemAddr8* addr, M4OSA_UInt32 newSize) * Used only in case of 3GP constant memory reader, to be able to realloc temporary AU * because max AU size can be reevaluated during reading * @return M4NO_ERROR: No error ****************************************************************************** */ static M4OSA_ERR M4MCS_intReallocTemporaryAU( M4OSA_MemAddr8 *addr, M4OSA_UInt32 newSize ) { if( *addr != M4OSA_NULL ) { free(*addr); *addr = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(newSize, M4MCS, (M4OSA_Char *)"Reallocation of temporary AU buffer"); if( *addr == M4OSA_NULL ) { return M4ERR_ALLOC; } } return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intVideoNullEncoding(M4MCS_InternalContext* pC) * @author Alexis Vapillon (NXP Software Vision) * @return M4NO_ERROR: No error ****************************************************************************** */ static M4OSA_ERR M4MCS_intVideoNullEncoding( M4MCS_InternalContext *pC ) { M4OSA_ERR err = M4NO_ERROR; /* Duration of the AU (find the next AU duration * to obtain a more precise video end cut) */ M4OSA_UInt32 videoAUDuration = 0; M4OSA_MemAddr8 WritebufferAdd = M4OSA_NULL; M4OSA_Int32 lastdecodedCTS = 0; M4_AccessUnit lReaderVideoAU; /**< Read video access unit */ if( pC->novideo ) return M4NO_ERROR; /* H.264 Trimming */ if( ( ( pC->bH264Trim == M4OSA_TRUE) && (pC->uiVideoAUCount < pC->m_pInstance->clip_sps.num_ref_frames) && (pC->uiBeginCutTime > 0)) || (( pC->uiVideoAUCount == 0) && (pC->uiBeginCutTime > 0)) ) { err = M4MCS_intVideoTranscoding(pC); return err; } if((pC->bLastDecodedFrameCTS == M4OSA_FALSE) && (pC->uiBeginCutTime > 0)) { // StageFright encoder does prefetch, the one frame we requested will not be written until // the encoder is closed, so do it now rather than in MCS_close if( ( M4NO_ERROR != err) || (M4MCS_kEncoderRunning != pC->encoderState) ) { M4OSA_TRACE1_2( "!!! M4MCS_intVideoNullEncoding ERROR : M4MCS_intVideoTranscoding " "returns 0x%X w/ encState=%d", err, pC->encoderState); return err; } /* Stop and close the encoder now to flush the frame (prefetch) */ if( pC->pVideoEncoderGlobalFcts->pFctStop != M4OSA_NULL ) { err = pC->pVideoEncoderGlobalFcts->pFctStop(pC->pViEncCtxt); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "!!! M4MCS_intVideoNullEncoding ERROR : encoder stop returns 0x%X", err); return err; } } pC->encoderState = M4MCS_kEncoderStopped; err = pC->pVideoEncoderGlobalFcts->pFctClose(pC->pViEncCtxt); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "!!! M4MCS_intVideoNullEncoding ERROR : encoder close returns 0x%X", err); return err; } pC->encoderState = M4MCS_kEncoderClosed; } if ((pC->EncodingVideoFormat = M4ENCODER_kNULL) && (pC->bLastDecodedFrameCTS == M4OSA_FALSE) && (pC->uiBeginCutTime > 0)) { pC->bLastDecodedFrameCTS = M4OSA_TRUE; err = pC->m_pVideoDecoder->m_pFctGetOption(pC->pViDecCtxt, M4DECODER_kOptionID_AVCLastDecodedFrameCTS, &lastdecodedCTS); if (M4NO_ERROR != err) { M4OSA_TRACE1_1( "M4MCS_intVideoNullEncoding: m_pVideoDecoder->m_pFctGetOption returns 0x%x!", err); return err; } /* Do not need video decoder any more, need to destroy it. Otherwise it * will call reader function which will cause frame lost during triming, * since the 3gp reader is shared between MCS and decoder.*/ if (M4OSA_NULL != pC->pViDecCtxt) { err = pC->m_pVideoDecoder->m_pFctDestroy(pC->pViDecCtxt); pC->pViDecCtxt = M4OSA_NULL; if (M4NO_ERROR != err) { M4OSA_TRACE1_1( "M4MCS_intVideoNullEncoding: decoder pFctDestroy returns 0x%x", err); return err; } } err = pC->m_pReader->m_pFctJump(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream, &lastdecodedCTS); if (M4NO_ERROR != err) { M4OSA_TRACE1_1( "M4MCS_intVideoNullEncoding: m_pFctJump(V) returns 0x%x!", err); return err; } /* Initializes an access Unit */ err = pC->m_pReader->m_pFctFillAuStruct(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream, &lReaderVideoAU); if (M4NO_ERROR != err) { M4OSA_TRACE1_1( "M4MCS_intVideoNullEncoding:m_pReader->m_pFctFillAuStruct(video)\ returns 0x%x", err); return err; } err = pC->m_pReaderDataIt->m_pFctGetNextAu(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream, &lReaderVideoAU); if (M4WAR_NO_MORE_AU == err) { M4OSA_TRACE2_0( "M4MCS_intVideoNullEncoding():\ m_pReaderDataIt->m_pFctGetNextAu(video) returns M4WAR_NO_MORE_AU"); /* The audio transcoding is finished */ pC->VideoState = M4MCS_kStreamState_FINISHED; return err; } else if (M4NO_ERROR != err) { M4OSA_TRACE1_1( "M4MCS_intVideoNullEncoding():\ m_pReaderDataIt->m_pFctGetNextAu(video) returns 0x%x", err); return err; } M4OSA_TRACE1_1( "### [TS_CHECK] M4MCS_intVideoNullEncoding video AU CTS: %d ", lReaderVideoAU.m_CTS); } pC->bLastDecodedFrameCTS = M4OSA_TRUE; /* Find the next AU duration to obtain a more precise video end cut*/ /** * Initializes a new AU if needed */ if (pC->ReaderVideoAU1.m_structSize == 0) { /** * Initializes an access Unit */ err = pC->m_pReader->m_pFctFillAuStruct(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream, &pC->ReaderVideoAU1); if (M4NO_ERROR != err) { M4OSA_TRACE1_1( "M4MCS_open(): m_pReader->m_pFctFillAuStruct(video) returns 0x%x", err); return err; } pC->m_pDataVideoAddress1 = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(pC->ReaderVideoAU1.m_maxsize, M4MCS, (M4OSA_Char *)"Temporary video AU1 buffer"); if (pC->m_pDataVideoAddress1 == M4OSA_NULL) { M4OSA_TRACE1_0("M4MCS_intVideoNullEncoding(): allocation error"); return M4ERR_ALLOC; } err = pC->m_pReaderDataIt->m_pFctGetNextAu(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream, &pC->ReaderVideoAU1); if( M4WAR_NO_MORE_AU == err ) { M4OSA_TRACE2_0( "M4MCS_intVideoNullEncoding():\ m_pReaderDataIt->m_pFctGetNextAu(video) returns M4WAR_NO_MORE_AU"); /* The audio transcoding is finished */ pC->VideoState = M4MCS_kStreamState_FINISHED; return err; } else if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intVideoNullEncoding(): m_pReaderDataIt->m_pFctGetNextAu(video)\ returns 0x%x", err); return err; } if( pC->ReaderVideoAU1.m_maxsize > pC->pReaderVideoStream->m_basicProperties.m_maxAUSize ) { /* Constant memory reader case, we need to reallocate the temporary buffers */ M4MCS_intReallocTemporaryAU((M4OSA_MemAddr8 *) &(pC->m_pDataVideoAddress1), pC->ReaderVideoAU1.m_maxsize); /* pC->m_pDataVideoAddress1 and pC->m_pDataVideoAddress2 must be reallocated at the same time */ /* because pC->pReaderVideoStream->m_basicProperties.m_maxAUSize take maximum value. Then the test "if(pC->ReaderVideoAU?.m_maxsize > pC->pReaderVideoStream-> m_basicProperties.m_maxAUSize)" is never true */ /* and the size of the second buffer is never changed. */ M4MCS_intReallocTemporaryAU((M4OSA_MemAddr8 *) &(pC->m_pDataVideoAddress2), pC->ReaderVideoAU1.m_maxsize); /* pC->m_pDataVideoAddress1 and pC->m_pDataVideoAddress2 must be reallocated at the same time */ /* Update stream properties */ pC->pReaderVideoStream->m_basicProperties.m_maxAUSize = pC->ReaderVideoAU1.m_maxsize; } memcpy((void *)pC->m_pDataVideoAddress1, (void *)pC->ReaderVideoAU1.m_dataAddress, pC->ReaderVideoAU1.m_size); } if( pC->ReaderVideoAU2.m_structSize == 0 ) { /** * Initializes an access Unit */ err = pC->m_pReader->m_pFctFillAuStruct(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream, &pC->ReaderVideoAU2); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_open(): m_pReader->m_pFctFillAuStruct(video) returns 0x%x", err); return err; } pC->m_pDataVideoAddress2 = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(pC->ReaderVideoAU2.m_maxsize, M4MCS, (M4OSA_Char *)"Temporary video AU buffer"); if( pC->m_pDataVideoAddress2 == M4OSA_NULL ) { M4OSA_TRACE1_0("M4MCS_intVideoNullEncoding(): allocation error"); return M4ERR_ALLOC; } } /** * Read the next video AU in the input file */ if( pC->ReaderVideoAU2.m_CTS > pC->ReaderVideoAU1.m_CTS ) { memcpy((void *) &pC->ReaderVideoAU, (void *) &pC->ReaderVideoAU2, sizeof(M4_AccessUnit)); err = pC->m_pReaderDataIt->m_pFctGetNextAu(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream, &pC->ReaderVideoAU1); if( pC->ReaderVideoAU1.m_maxsize > pC->pReaderVideoStream->m_basicProperties.m_maxAUSize ) { /* Constant memory reader case, we need to reallocate the temporary buffers */ M4MCS_intReallocTemporaryAU((M4OSA_MemAddr8 *) &(pC->m_pDataVideoAddress1), pC->ReaderVideoAU1.m_maxsize); /* pC->m_pDataVideoAddress1 and pC->m_pDataVideoAddress2 must be reallocated at the same time */ /* because pC->pReaderVideoStream->m_basicProperties.m_maxAUSize take maximum value. Then the test "if(pC->ReaderVideoAU?.m_maxsize > pC->pReaderVideoStream-> m_basicProperties.m_maxAUSize)" is never true */ /* and the size of the second buffer is never changed. */ M4MCS_intReallocTemporaryAU((M4OSA_MemAddr8 *) &(pC->m_pDataVideoAddress2), pC->ReaderVideoAU1.m_maxsize); /* pC->m_pDataVideoAddress1 and pC->m_pDataVideoAddress2 must be reallocated at the same time */ /* Update stream properties */ pC->pReaderVideoStream->m_basicProperties.m_maxAUSize = pC->ReaderVideoAU1.m_maxsize; } memcpy((void *)pC->m_pDataVideoAddress1, (void *)pC->ReaderVideoAU1.m_dataAddress, pC->ReaderVideoAU1.m_size); videoAUDuration = pC->ReaderVideoAU1.m_CTS - pC->ReaderVideoAU2.m_CTS; pC->ReaderVideoAU.m_dataAddress = pC->m_pDataVideoAddress2; } else { memcpy((void *) &pC->ReaderVideoAU, (void *) &pC->ReaderVideoAU1, sizeof(M4_AccessUnit)); err = pC->m_pReaderDataIt->m_pFctGetNextAu(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderVideoStream, &pC->ReaderVideoAU2); if( pC->ReaderVideoAU2.m_maxsize > pC->pReaderVideoStream->m_basicProperties.m_maxAUSize ) { /* Constant memory reader case, we need to reallocate the temporary buffers */ M4MCS_intReallocTemporaryAU((M4OSA_MemAddr8 *) &(pC->m_pDataVideoAddress2), pC->ReaderVideoAU2.m_maxsize); /* pC->m_pDataVideoAddress1 and pC->m_pDataVideoAddress2 must be reallocated at the same time */ /* because pC->pReaderVideoStream->m_basicProperties.m_maxAUSize take maximum value. Then the test "if(pC->ReaderVideoAU?.m_maxsize > pC->pReaderVideoStream-> m_basicProperties.m_maxAUSize)" is never true */ /* and the size of the second buffer is never changed. */ M4MCS_intReallocTemporaryAU((M4OSA_MemAddr8 *) &(pC->m_pDataVideoAddress1), pC->ReaderVideoAU2.m_maxsize); /* pC->m_pDataVideoAddress1 and pC->m_pDataVideoAddress2 must be reallocated at the same time */ /* Update stream properties */ pC->pReaderVideoStream->m_basicProperties.m_maxAUSize = pC->ReaderVideoAU2.m_maxsize; } memcpy((void *)pC->m_pDataVideoAddress2, (void *)pC->ReaderVideoAU2.m_dataAddress, pC->ReaderVideoAU2.m_size); videoAUDuration = pC->ReaderVideoAU2.m_CTS - pC->ReaderVideoAU1.m_CTS; pC->ReaderVideoAU.m_dataAddress = pC->m_pDataVideoAddress1; } if( M4WAR_NO_MORE_AU == err ) { M4OSA_TRACE2_0( "M4MCS_intVideoNullEncoding():\ m_pReaderDataIt->m_pFctGetNextAu(video) returns M4WAR_NO_MORE_AU"); /* The video transcoding is finished */ pC->VideoState = M4MCS_kStreamState_FINISHED; return err; } else if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intVideoNullEncoding(): m_pReaderDataIt->m_pFctGetNextAu(Video) returns 0x%x", err); return err; } else { /** * Prepare the writer AU */ err = pC->pWriterDataFcts->pStartAU(pC->pWriterContext, M4MCS_WRITER_VIDEO_STREAM_ID, &pC->WriterVideoAU); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intVideoNullEncoding(): pWriterDataFcts->pStartAU(Video) returns 0x%x", err); return err; } /** * Copy video data from reader AU to writer AU */ M4OSA_TRACE3_1( "M4MCS_intVideoNullEncoding(): Copying video AU: size=%d", pC->ReaderVideoAU.m_size); /* + CRLV6775 -H.264 Trimming */ if( M4OSA_TRUE == pC->bH264Trim ) { if( pC->H264MCSTempBufferSize < (pC->ReaderVideoAU.m_size + 2048) ) { pC->H264MCSTempBufferSize = (pC->ReaderVideoAU.m_size + 2048); if( pC->H264MCSTempBuffer != M4OSA_NULL ) { free(pC->H264MCSTempBuffer); } pC->H264MCSTempBuffer = (M4OSA_UInt8 *)M4OSA_32bitAlignedMalloc(pC->H264MCSTempBufferSize, M4MCS, (M4OSA_Char *)"pC->H264MCSTempBuffer"); if( pC->H264MCSTempBuffer == M4OSA_NULL ) { M4OSA_TRACE1_0( "M4MCS_intVideoNullEncoding(): allocation error"); return M4ERR_ALLOC; } } pC->H264MCSTempBufferDataSize = pC->H264MCSTempBufferSize; err = H264MCS_ProcessNALU(pC->m_pInstance, (M4OSA_UInt8 *)pC->ReaderVideoAU.m_dataAddress, pC->ReaderVideoAU.m_size, pC->H264MCSTempBuffer, (M4OSA_Int32 *)&pC->H264MCSTempBufferDataSize); if( pC->m_pInstance->is_done == 1 ) { M4MCS_convetFromByteStreamtoNALStream( (M4OSA_UInt8 *)pC->ReaderVideoAU.m_dataAddress , pC->ReaderVideoAU.m_size); memcpy((void *)pC->WriterVideoAU.dataAddress, (void *)(pC->ReaderVideoAU.m_dataAddress + 4), pC->ReaderVideoAU.m_size - 4); pC->WriterVideoAU.size = pC->ReaderVideoAU.m_size - 4; WritebufferAdd = (M4OSA_MemAddr8)pC->WriterVideoAU.dataAddress; } else { memcpy((void *)pC->WriterVideoAU.dataAddress, (void *)(pC->H264MCSTempBuffer + 4), pC->H264MCSTempBufferDataSize - 4); pC->WriterVideoAU.size = pC->H264MCSTempBufferDataSize - 4; WritebufferAdd = (M4OSA_MemAddr8)pC->WriterVideoAU.dataAddress; } } /* H.264 Trimming */ else { memcpy((void *)pC->WriterVideoAU.dataAddress, (void *)pC->ReaderVideoAU.m_dataAddress, pC->ReaderVideoAU.m_size); pC->WriterVideoAU.size = pC->ReaderVideoAU.m_size; } /** * Convert CTS unit from milliseconds to timescale */ pC->WriterVideoAU.CTS = (M4OSA_Time)((( pC->ReaderVideoAU.m_CTS - pC->dViDecStartingCts) * (pC->WriterVideoStream.timeScale / 1000.0))); pC->WriterVideoAU.nbFrag = 0; pC->WriterVideoAU.attribute = pC->ReaderVideoAU.m_attribute; M4OSA_TRACE3_1("M4MCS_intVideoNullEncoding(): video AU: CTS=%d ms", pC->WriterVideoAU.CTS); /** * Write it to the output file */ pC->uiVideoAUCount++; err = pC->pWriterDataFcts->pProcessAU(pC->pWriterContext, M4MCS_WRITER_VIDEO_STREAM_ID, &pC->WriterVideoAU); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intVideoNullEncoding(): pWriterDataFcts->pProcessAU(Video) returns 0x%x", err); return err; } /* + CRLV6775 -H.264 Trimming */ if( M4OSA_TRUE == pC->bH264Trim ) { if( pC->m_pInstance->is_done == 1 ) { memcpy((void *)(WritebufferAdd - 4), (void *)(pC->ReaderVideoAU.m_dataAddress), 4); } else { memcpy((void *)(WritebufferAdd - 4), (void *)(pC->H264MCSTempBuffer), 4); } } /* H.264 Trimming */ } /** * Check for end cut. */ /* Bug fix 11/12/2008: We absolutely want to have less or same video duration -> (2*videoAUDuration) to have a more precise end cut*/ if( pC->ReaderVideoAU.m_CTS + (2 *videoAUDuration) > pC->uiEndCutTime ) { pC->VideoState = M4MCS_kStreamState_FINISHED; } /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_intVideoNullEncoding(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intVideoTranscoding(M4MCS_InternalContext* pC) * @author Alexis Vapillon (NXP Software Vision) * @return M4NO_ERROR: No error ****************************************************************************** */ static M4OSA_ERR M4MCS_intVideoTranscoding( M4MCS_InternalContext *pC ) { M4OSA_ERR err = M4NO_ERROR; M4_MediaTime mtTranscodedTime = 0.0; M4ENCODER_FrameMode FrameMode; M4OSA_Int32 derive = 0; /** * Get video CTS to decode */ mtTranscodedTime = pC->dViDecCurrentCts; FrameMode = M4ENCODER_kNormalFrame; /** * Decode video */ M4OSA_TRACE3_1( "M4MCS_intVideoTranscoding(): Calling m_pVideoDecoder->m_pFctDecode(%.2f)", mtTranscodedTime); pC->isRenderDup = M4OSA_FALSE; err = pC->m_pVideoDecoder->m_pFctDecode(pC->pViDecCtxt, &mtTranscodedTime, M4OSA_FALSE, 0); if( M4WAR_NO_MORE_AU == err ) { FrameMode = M4ENCODER_kLastFrame; /**< We will give this value to the encoder to ask for the end of the encoding */ pC->VideoState = M4MCS_kStreamState_FINISHED; } else if( err == M4WAR_VIDEORENDERER_NO_NEW_FRAME ) { M4OSA_TRACE2_0("Decoding output the same frame as before 3"); pC->isRenderDup = M4OSA_TRUE; } else if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intVideoTranscoding(): m_pVideoDecoder->m_pFctDecode returns 0x%x!", err); return err; } /** * Check for end cut. * We must check here if the end cut is reached, because in that case we must * call the last encode step (-> bLastFrame set to true) */ if( ( pC->dViDecCurrentCts + pC->dCtsIncrement ) >= (pC->uiEndCutTime + M4MCS_ABS(pC->dViDecStartingCts - pC->uiBeginCutTime)) ) { FrameMode = M4ENCODER_kLastFrame; /**< We will give this value to the encoder to ask for the end of the encoding */ pC->VideoState = M4MCS_kStreamState_FINISHED; derive = (M4OSA_Int32)(( pC->dViDecCurrentCts + pC->dCtsIncrement + 0.5) - (pC->uiEndCutTime + M4MCS_ABS(pC->dViDecStartingCts - pC->uiBeginCutTime))); } /* Update starting CTS to have a more precise value ( the begin cut is not a real CTS)*/ if( pC->uiVideoAUCount == 0 ) { pC->dViDecStartingCts = mtTranscodedTime; pC->dViDecCurrentCts = pC->dViDecStartingCts; } /** * Encode video */ M4OSA_TRACE3_1( "M4MCS_intVideoTranscoding(): Calling pVideoEncoderGlobalFcts->pFctEncode with videoCts\ = %.2f",pC->ReaderVideoAU.m_CTS); pC->uiVideoAUCount++; /* update the given duration (the begin cut is not a real CTS)*/ err = pC->pVideoEncoderGlobalFcts->pFctEncode(pC->pViEncCtxt, M4OSA_NULL, (pC->dViDecCurrentCts - pC->dViDecStartingCts - (derive >> 1)), FrameMode); return err; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intGetInputClipProperties(M4MCS_InternalContext* pContext) * @author Dounya Manai (NXP Software Vision) * @brief Retrieve the properties of the audio and video streams from the input file. * @param pContext (IN) MCS context * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (If Debug Level >= 2) ****************************************************************************** */ static M4OSA_ERR M4MCS_intGetInputClipProperties( M4MCS_InternalContext *pC ) { M4DECODER_MPEG4_DecoderConfigInfo DecConfInfo; M4READER_3GP_H263Properties H263prop; M4OSA_ERR err; M4OSA_UInt32 videoBitrate; M4DECODER_VideoSize videoSize; M4_AACType iAacType = 0; /** * Check input parameters */ M4OSA_DEBUG_IF2(M4OSA_NULL == pC, M4ERR_PARAMETER, "M4MCS_intGetInputClipProperties: pC is M4OSA_NULL"); /** * Reset common characteristics */ pC->InputFileProperties.bAnalysed = M4OSA_FALSE; pC->InputFileProperties.FileType = 0; pC->InputFileProperties.Version[0] = M4VIDEOEDITING_VERSION_MAJOR; pC->InputFileProperties.Version[1] = M4VIDEOEDITING_VERSION_MINOR; pC->InputFileProperties.Version[2] = M4VIDEOEDITING_VERSION_REVISION; pC->InputFileProperties.uiClipDuration = 0; memset((void *) &pC->InputFileProperties.ftyp, 0, sizeof(M4VIDEOEDITING_FtypBox)); /** * Reset video characteristics */ pC->InputFileProperties.VideoStreamType = M4VIDEOEDITING_kNoneVideo; pC->InputFileProperties.uiClipVideoDuration = 0; pC->InputFileProperties.uiVideoBitrate = 0; pC->InputFileProperties.uiVideoMaxAuSize = 0; pC->InputFileProperties.uiVideoWidth = 0; pC->InputFileProperties.uiVideoHeight = 0; pC->InputFileProperties.uiVideoTimeScale = 0; pC->InputFileProperties.fAverageFrameRate = 0.0; pC->InputFileProperties.uiVideoLevel = M4VIDEOEDITING_VIDEO_UNKNOWN_LEVEL; pC->InputFileProperties.uiVideoProfile = M4VIDEOEDITING_VIDEO_UNKNOWN_PROFILE; pC->InputFileProperties.bMPEG4dataPartition = M4OSA_FALSE; pC->InputFileProperties.bMPEG4rvlc = M4OSA_FALSE; pC->InputFileProperties.bMPEG4resynchMarker = M4OSA_FALSE; /** * Reset audio characteristics */ pC->InputFileProperties.AudioStreamType = M4VIDEOEDITING_kNoneAudio; pC->InputFileProperties.uiClipAudioDuration = 0; pC->InputFileProperties.uiAudioBitrate = 0; pC->InputFileProperties.uiAudioMaxAuSize = 0; pC->InputFileProperties.uiNbChannels = 0; pC->InputFileProperties.uiSamplingFrequency = 0; pC->InputFileProperties.uiExtendedSamplingFrequency = 0; pC->InputFileProperties.uiDecodedPcmSize = 0; /* Reset compatibility chart (not used in MCS) */ pC->InputFileProperties.bVideoIsEditable = M4OSA_FALSE; pC->InputFileProperties.bAudioIsEditable = M4OSA_FALSE; pC->InputFileProperties.bVideoIsCompatibleWithMasterClip = M4OSA_FALSE; pC->InputFileProperties.bAudioIsCompatibleWithMasterClip = M4OSA_FALSE; /** * Video stream properties */ if( M4OSA_NULL != pC->pReaderVideoStream ) { switch( pC->pReaderVideoStream->m_basicProperties.m_streamType ) { case M4DA_StreamTypeVideoMpeg4: pC->InputFileProperties.VideoStreamType = M4VIDEOEDITING_kMPEG4; break; case M4DA_StreamTypeVideoH263: pC->InputFileProperties.VideoStreamType = M4VIDEOEDITING_kH263; break; case M4DA_StreamTypeVideoMpeg4Avc: pC->InputFileProperties.VideoStreamType = M4VIDEOEDITING_kH264; break; case M4DA_StreamTypeUnknown: default: pC->InputFileProperties.VideoStreamType = M4VIDEOEDITING_kUnsupportedVideo; break; } /* if bitrate not available retrieve an estimation of the overall bitrate */ pC->InputFileProperties.uiVideoBitrate = pC->pReaderVideoStream->m_basicProperties.m_averageBitRate; if( 0 == pC->InputFileProperties.uiVideoBitrate ) { pC->m_pReader->m_pFctGetOption(pC->pReaderContext, M4READER_kOptionID_Bitrate, &videoBitrate); if( M4OSA_NULL != pC->pReaderAudioStream ) { /* we get the overall bitrate, substract the audio bitrate if any */ videoBitrate -= pC->pReaderAudioStream->m_basicProperties.m_averageBitRate; } pC->InputFileProperties.uiVideoBitrate = videoBitrate; } /** * Retrieve the Profile & Level */ if( ( M4VIDEOEDITING_kH263 != pC->InputFileProperties.VideoStreamType) && (M4VIDEOEDITING_kH264 != pC->InputFileProperties.VideoStreamType) ) { /* Use the DSI parsing function from the external video shell decoder. See the comments in M4VSS3GPP_ClipAnalysis.c, it's pretty much the same issue. */ err = M4DECODER_EXTERNAL_ParseVideoDSI(pC->pReaderVideoStream-> m_basicProperties.m_pDecoderSpecificInfo, pC->pReaderVideoStream-> m_basicProperties.m_decoderSpecificInfoSize, &DecConfInfo, &videoSize); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intGetInputClipProperties():\ M4DECODER_EXTERNAL_ParseVideoDSI returns 0x%08X", err); return err; } pC->pReaderVideoStream->m_videoWidth = videoSize.m_uiWidth; pC->pReaderVideoStream->m_videoHeight = videoSize.m_uiHeight; pC->InputFileProperties.uiVideoTimeScale = DecConfInfo.uiTimeScale; pC->InputFileProperties.bMPEG4dataPartition = DecConfInfo.bDataPartition; pC->InputFileProperties.bMPEG4rvlc = DecConfInfo.bUseOfRVLC; pC->InputFileProperties.bMPEG4resynchMarker = DecConfInfo.uiUseOfResynchMarker; err = getMPEG4ProfileAndLevel(DecConfInfo.uiProfile, &(pC->InputFileProperties.uiVideoProfile), &(pC->InputFileProperties.uiVideoLevel)); if ( M4NO_ERROR != err ) { M4OSA_TRACE1_1("M4MCS_intGetInputClipProperties():\ getMPEG4ProfileAndLevel returns 0x%08X", err); return err; } } else if( M4VIDEOEDITING_kH263 == pC->InputFileProperties.VideoStreamType ) { err = getH263ProfileAndLevel(pC->pReaderVideoStream-> m_basicProperties.m_pDecoderSpecificInfo, pC->pReaderVideoStream->m_basicProperties.m_decoderSpecificInfoSize, &(pC->InputFileProperties.uiVideoProfile), &(pC->InputFileProperties.uiVideoLevel)); if ( M4NO_ERROR != err ) { M4OSA_TRACE1_1("M4MCS_intGetInputClipProperties():\ getH263ProfileAndLevel returns 0x%08X", err); return err; } /* For h263 set default timescale : 30000:1001 */ pC->InputFileProperties.uiVideoTimeScale = 30000; } else if ( M4VIDEOEDITING_kH264 == pC->InputFileProperties.VideoStreamType ) { pC->InputFileProperties.uiVideoTimeScale = 30000; err = getAVCProfileAndLevel(pC->pReaderVideoStream-> m_basicProperties.m_pDecoderSpecificInfo, pC->pReaderVideoStream->m_basicProperties.m_decoderSpecificInfoSize, &(pC->InputFileProperties.uiVideoProfile), &(pC->InputFileProperties.uiVideoLevel)); if ( M4NO_ERROR != err ) { M4OSA_TRACE1_1("M4MCS_intGetInputClipProperties():\ getAVCProfileAndLevel returns 0x%08X", err); return err; } } /* Here because width x height is correct only after dsi parsing (done in create decoder) */ pC->InputFileProperties.uiVideoHeight = pC->pReaderVideoStream->m_videoHeight; pC->InputFileProperties.uiVideoWidth = pC->pReaderVideoStream->m_videoWidth; pC->InputFileProperties.uiClipVideoDuration = (M4OSA_UInt32)pC->pReaderVideoStream->m_basicProperties.m_duration; pC->InputFileProperties.fAverageFrameRate = pC->pReaderVideoStream->m_averageFrameRate; pC->InputFileProperties.uiVideoMaxAuSize = pC->pReaderVideoStream->m_basicProperties.m_maxAUSize; pC->InputFileProperties.videoRotationDegrees = pC->pReaderVideoStream->videoRotationDegrees; } else { if( M4OSA_TRUE == pC->bUnsupportedVideoFound ) { pC->InputFileProperties.VideoStreamType = M4VIDEOEDITING_kUnsupportedVideo; } else { pC->InputFileProperties.VideoStreamType = M4VIDEOEDITING_kNoneVideo; } } /** * Audio stream properties */ if( M4OSA_NULL != pC->pReaderAudioStream ) { switch( pC->pReaderAudioStream->m_basicProperties.m_streamType ) { case M4DA_StreamTypeAudioAmrNarrowBand: pC->InputFileProperties.AudioStreamType = M4VIDEOEDITING_kAMR_NB; break; case M4DA_StreamTypeAudioAac: pC->InputFileProperties.AudioStreamType = M4VIDEOEDITING_kAAC; break; case M4DA_StreamTypeAudioMp3: pC->InputFileProperties.AudioStreamType = M4VIDEOEDITING_kMP3; break; case M4DA_StreamTypeAudioEvrc: pC->InputFileProperties.AudioStreamType = M4VIDEOEDITING_kEVRC; break; case M4DA_StreamTypeUnknown: default: pC->InputFileProperties.AudioStreamType = M4VIDEOEDITING_kUnsupportedAudio; break; } if( ( M4OSA_NULL != pC->m_pAudioDecoder) && (M4OSA_NULL == pC->pAudioDecCtxt) ) { M4OSA_TRACE3_1( "M4MCS_intGetInputClipProperties: calling CreateAudioDecoder, userData= 0x%x", pC->m_pCurrentAudioDecoderUserData); if( M4OSA_FALSE == pC->bExtOMXAudDecoder ) { err = M4MCS_intCheckAndGetCodecProperties(pC); } else { err = pC->m_pAudioDecoder->m_pFctCreateAudioDec( &pC->pAudioDecCtxt, pC->pReaderAudioStream, pC->m_pCurrentAudioDecoderUserData); if( M4NO_ERROR == err ) { /* AAC properties*/ //get from Reader; temporary, till Audio decoder shell API available to //get the AAC properties pC->AacProperties.aNumChan = pC->pReaderAudioStream->m_nbChannels; pC->AacProperties.aSampFreq = pC->pReaderAudioStream->m_samplingFrequency; err = pC->m_pAudioDecoder->m_pFctGetOptionAudioDec( pC->pAudioDecCtxt, M4AD_kOptionID_StreamType, (M4OSA_DataOption) &iAacType); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intGetInputClipProperties:\ m_pAudioDecoder->m_pFctGetOptionAudioDec returns err 0x%x", err); iAacType = M4_kAAC; //set to default err = M4NO_ERROR; } else { M4OSA_TRACE3_1( "M4MCS_intGetInputClipProperties:\ m_pAudioDecoder->m_pFctGetOptionAudioDec returns streamType %d", iAacType); } switch( iAacType ) { case M4_kAAC: pC->AacProperties.aSBRPresent = 0; pC->AacProperties.aPSPresent = 0; break; case M4_kAACplus: pC->AacProperties.aSBRPresent = 1; pC->AacProperties.aPSPresent = 0; pC->AacProperties.aExtensionSampFreq = pC->pReaderAudioStream-> m_samplingFrequency; //TODO break; case M4_keAACplus: pC->AacProperties.aSBRPresent = 1; pC->AacProperties.aPSPresent = 1; pC->AacProperties.aExtensionSampFreq = pC->pReaderAudioStream-> m_samplingFrequency; //TODO break; case M4_kUnknown: break; default: break; } M4OSA_TRACE3_2( "M4MCS_intGetInputClipProperties: AAC NBChans=%d, SamplFreq=%d", pC->AacProperties.aNumChan, pC->AacProperties.aSampFreq); } } if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intGetInputClipProperties:\ m_pAudioDecoder->m_pFctCreateAudioDec returns 0x%x", err); return err; } } //EVRC if( pC->pReaderAudioStream->m_basicProperties.m_streamType == M4DA_StreamTypeAudioEvrc ) { /* decoder not implemented yet, provide some default values for the null encoding */ pC->pReaderAudioStream->m_nbChannels = 1; pC->pReaderAudioStream->m_samplingFrequency = 8000; } /** * Bugfix P4ME00001128: With some IMTC files, the AMR bit rate is 0 kbps according the GetProperties function */ if( 0 == pC->pReaderAudioStream->m_basicProperties.m_averageBitRate ) { if( M4VIDEOEDITING_kAMR_NB == pC->InputFileProperties.AudioStreamType ) { /** * Better returning a guessed 12.2 kbps value than a sure-to-be-false 0 kbps value! */ pC->InputFileProperties.uiAudioBitrate = M4VIDEOEDITING_k12_2_KBPS; } else if( M4VIDEOEDITING_kEVRC == pC->InputFileProperties.AudioStreamType ) { /** * Better returning a guessed 8.5 kbps value than a sure-to-be-false 0 kbps value! */ pC->InputFileProperties.uiAudioBitrate = M4VIDEOEDITING_k9_2_KBPS; } else { M4OSA_UInt32 FileBitrate; /* Can happen also for aac, in this case we calculate an approximative */ /* value from global bitrate and video bitrate */ err = pC->m_pReader->m_pFctGetOption(pC->pReaderContext, M4READER_kOptionID_Bitrate, (M4OSA_DataOption) &FileBitrate); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intGetInputClipProperties: M4READER_kOptionID_Bitrate returns 0x%x", err); return err; } pC->InputFileProperties.uiAudioBitrate = FileBitrate - pC-> InputFileProperties. uiVideoBitrate /* normally setted to 0, if no video */; } } else { pC->InputFileProperties.uiAudioBitrate = pC->pReaderAudioStream->m_basicProperties.m_averageBitRate; } pC->InputFileProperties.uiNbChannels = pC->pReaderAudioStream->m_nbChannels; pC->InputFileProperties.uiSamplingFrequency = pC->pReaderAudioStream->m_samplingFrequency; pC->InputFileProperties.uiClipAudioDuration = (M4OSA_UInt32)pC->pReaderAudioStream->m_basicProperties.m_duration; pC->InputFileProperties.uiAudioMaxAuSize = pC->pReaderAudioStream->m_basicProperties.m_maxAUSize; /* Bug: with aac, value is 0 until decoder start() is called */ pC->InputFileProperties.uiDecodedPcmSize = pC->pReaderAudioStream->m_byteFrameLength * pC->pReaderAudioStream->m_byteSampleSize * pC->pReaderAudioStream->m_nbChannels; /* New aac properties */ if( M4DA_StreamTypeAudioAac == pC->pReaderAudioStream->m_basicProperties.m_streamType ) { pC->InputFileProperties.uiNbChannels = pC->AacProperties.aNumChan; pC->InputFileProperties.uiSamplingFrequency = pC->AacProperties.aSampFreq; if( pC->AacProperties.aSBRPresent ) { pC->InputFileProperties.AudioStreamType = M4VIDEOEDITING_kAACplus; pC->InputFileProperties.uiExtendedSamplingFrequency = pC->AacProperties.aExtensionSampFreq; } if( pC->AacProperties.aPSPresent ) { pC->InputFileProperties.AudioStreamType = M4VIDEOEDITING_keAACplus; } } } else { if( M4OSA_TRUE == pC->bUnsupportedAudioFound ) { pC->InputFileProperties.AudioStreamType = M4VIDEOEDITING_kUnsupportedAudio; } else { pC->InputFileProperties.AudioStreamType = M4VIDEOEDITING_kNoneAudio; } } /* Get 'ftyp' atom */ err = pC->m_pReader->m_pFctGetOption(pC->pReaderContext, M4READER_kOptionID_3gpFtypBox, &pC->InputFileProperties.ftyp); /* Analysis is successful */ if( pC->InputFileProperties.uiClipVideoDuration > pC->InputFileProperties.uiClipAudioDuration ) pC->InputFileProperties.uiClipDuration = pC->InputFileProperties.uiClipVideoDuration; else pC->InputFileProperties.uiClipDuration = pC->InputFileProperties.uiClipAudioDuration; pC->InputFileProperties.FileType = pC->InputFileType; pC->InputFileProperties.bAnalysed = M4OSA_TRUE; return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_UInt32 M4MCS_intGetFrameSize_AMRNB(M4OSA_MemAddr8 pAudioFrame) * @brief Return the length, in bytes, of the AMR Narrow-Band frame contained in the given buffer * @note * @param pCpAudioFrame (IN) AMRNB frame * @return M4NO_ERROR: No error ****************************************************************************** */ static M4OSA_UInt32 M4MCS_intGetFrameSize_AMRNB( M4OSA_MemAddr8 pAudioFrame ) { M4OSA_UInt32 frameSize = 0; M4OSA_UInt32 frameType = ( ( *pAudioFrame) &(0xF << 3)) >> 3; switch( frameType ) { case 0: frameSize = 95; break; /* 4750 bps */ case 1: frameSize = 103; break; /* 5150 bps */ case 2: frameSize = 118; break; /* 5900 bps */ case 3: frameSize = 134; break; /* 6700 bps */ case 4: frameSize = 148; break; /* 7400 bps */ case 5: frameSize = 159; break; /* 7950 bps */ case 6: frameSize = 204; break; /* 10200 bps */ case 7: frameSize = 244; break; /* 12000 bps */ case 8: frameSize = 39; break; /* SID (Silence) */ case 15: frameSize = 0; break; /* No data */ default: M4OSA_TRACE3_0( "M4MCS_intGetFrameSize_AMRNB(): Corrupted AMR frame! returning 0."); return 0; } return (1 + (( frameSize + 7) / 8)); } /** ****************************************************************************** * M4OSA_UInt32 M4MCS_intGetFrameSize_EVRC(M4OSA_MemAddr8 pAudioFrame) * @brief Return the length, in bytes, of the EVRC frame contained in the given buffer * @note * 0 1 2 3 * +-+-+-+-+ * |fr type| RFC 3558 * +-+-+-+-+ * * Frame Type: 4 bits * The frame type indicates the type of the corresponding codec data * frame in the RTP packet. * * For EVRC and SMV codecs, the frame type values and size of the * associated codec data frame are described in the table below: * * Value Rate Total codec data frame size (in octets) * --------------------------------------------------------- * 0 Blank 0 (0 bit) * 1 1/8 2 (16 bits) * 2 1/4 5 (40 bits; not valid for EVRC) * 3 1/2 10 (80 bits) * 4 1 22 (171 bits; 5 padded at end with zeros) * 5 Erasure 0 (SHOULD NOT be transmitted by sender) * * @param pCpAudioFrame (IN) EVRC frame * @return M4NO_ERROR: No error ****************************************************************************** */ static M4OSA_UInt32 M4MCS_intGetFrameSize_EVRC( M4OSA_MemAddr8 pAudioFrame ) { M4OSA_UInt32 frameSize = 0; M4OSA_UInt32 frameType = ( *pAudioFrame) &0x0F; switch( frameType ) { case 0: frameSize = 0; break; /* blank */ case 1: frameSize = 16; break; /* 1/8 */ case 2: frameSize = 40; break; /* 1/4 */ case 3: frameSize = 80; break; /* 1/2 */ case 4: frameSize = 171; break; /* 1 */ case 5: frameSize = 0; break; /* erasure */ default: M4OSA_TRACE3_0( "M4MCS_intGetFrameSize_EVRC(): Corrupted EVRC frame! returning 0."); return 0; } return (1 + (( frameSize + 7) / 8)); } /** ****************************************************************************** * M4OSA_ERR M4MCS_intCheckMaxFileSize(M4MCS_Context pContext) * @brief Check if max file size is greater enough to encode a file with the * current selected bitrates and duration. * @param pContext (IN) MCS context * @return M4NO_ERROR * @return M4MCS_ERR_MAXFILESIZE_TOO_SMALL ****************************************************************************** */ static M4OSA_ERR M4MCS_intCheckMaxFileSize( M4MCS_Context pContext ) { M4MCS_InternalContext *pC = (M4MCS_InternalContext *)(pContext); M4OSA_UInt32 duration; M4OSA_UInt32 audiobitrate; M4OSA_UInt32 videobitrate; /* free file size : OK */ if( pC->uiMaxFileSize == 0 ) return M4NO_ERROR; /* duration */ if( pC->uiEndCutTime == 0 ) { duration = pC->InputFileProperties.uiClipDuration - pC->uiBeginCutTime; } else { duration = pC->uiEndCutTime - pC->uiBeginCutTime; } /* audio bitrate */ if( pC->noaudio ) { audiobitrate = 0; } else if( pC->AudioEncParams.Format == M4ENCODER_kAudioNULL ) { audiobitrate = pC->InputFileProperties.uiAudioBitrate; } else if( pC->uiAudioBitrate == M4VIDEOEDITING_kUndefinedBitrate ) { switch( pC->AudioEncParams.Format ) { case M4ENCODER_kAMRNB: audiobitrate = M4VIDEOEDITING_k12_2_KBPS; break; //EVRC // case M4ENCODER_kEVRC: // audiobitrate = M4VIDEOEDITING_k9_2_KBPS; // break; default: /* AAC and MP3*/ audiobitrate = (pC->AudioEncParams.ChannelNum == M4ENCODER_kMono) ? M4VIDEOEDITING_k16_KBPS : M4VIDEOEDITING_k32_KBPS; break; } } else { audiobitrate = pC->uiAudioBitrate; } /* video bitrate */ if( pC->novideo ) { videobitrate = 0; } else if( pC->EncodingVideoFormat == M4ENCODER_kNULL ) { videobitrate = pC->InputFileProperties.uiVideoBitrate; } else if( pC->uiVideoBitrate == M4VIDEOEDITING_kUndefinedBitrate ) { videobitrate = M4VIDEOEDITING_k16_KBPS; } else { videobitrate = pC->uiVideoBitrate; } /* max file size */ if( (M4OSA_UInt32)pC->uiMaxFileSize < (M4OSA_UInt32)(M4MCS_MOOV_OVER_FILESIZE_RATIO * (audiobitrate + videobitrate) * (duration / 8000.0)) ) return M4MCS_ERR_MAXFILESIZE_TOO_SMALL; else return M4NO_ERROR; } /** ****************************************************************************** * M4VIDEOEDITING_Bitrate M4MCS_intGetNearestBitrate(M4OSA_UInt32 freebitrate, M4OSA_Int8 mode) * @brief Returns the closest bitrate value from the enum list of type M4VIDEOEDITING_Bitrate * @param freebitrate: unsigned int value * @param mode: -1:previous,0:current,1:next * @return bitrate value in enum list M4VIDEOEDITING_Bitrate ****************************************************************************** */ static M4VIDEOEDITING_Bitrate M4MCS_intGetNearestBitrate( M4OSA_Int32 freebitrate, M4OSA_Int8 mode ) { M4OSA_Int32 bitarray [] = { 0, M4VIDEOEDITING_k16_KBPS, M4VIDEOEDITING_k24_KBPS, M4VIDEOEDITING_k32_KBPS, M4VIDEOEDITING_k48_KBPS, M4VIDEOEDITING_k64_KBPS, M4VIDEOEDITING_k96_KBPS, M4VIDEOEDITING_k128_KBPS, M4VIDEOEDITING_k192_KBPS, M4VIDEOEDITING_k256_KBPS, M4VIDEOEDITING_k288_KBPS, M4VIDEOEDITING_k384_KBPS, M4VIDEOEDITING_k512_KBPS, M4VIDEOEDITING_k800_KBPS, M4VIDEOEDITING_k2_MBPS, M4VIDEOEDITING_k5_MBPS, M4VIDEOEDITING_k8_MBPS, /*+ New Encoder bitrates */ M4OSA_INT32_MAX }; const M4OSA_UInt32 nbbitrates = 14; M4OSA_UInt32 i; for ( i = 0; freebitrate >= bitarray[i]; i++ ); switch( mode ) { case -1: /* previous */ if( i <= 2 ) return 0; else return bitarray[i - 2]; break; case 0: /* current */ if( i <= 1 ) return 0; else return bitarray[i - 1]; break; case 1: /* next */ if( i >= nbbitrates ) return M4OSA_INT32_MAX; else return bitarray[i]; break; } return 0; } /** ****************************************************************************** * M4OSA_ERR M4MCS_intCleanUp_ReadersDecoders(M4MCS_InternalContext* pC); * @brief Free all resources allocated by M4MCS_open() * @param pContext (IN) MCS context * @return M4NO_ERROR: No error ****************************************************************************** */ static M4OSA_ERR M4MCS_intCleanUp_ReadersDecoders( M4MCS_InternalContext *pC ) { M4OSA_ERR err = M4NO_ERROR; M4OSA_TRACE2_1("M4MCS_intCleanUp_ReadersDecoders called with pC=0x%x", pC); /**/ /* ----- Free video decoder stuff, if needed ----- */ if( M4OSA_NULL != pC->pViDecCtxt ) { err = pC->m_pVideoDecoder->m_pFctDestroy(pC->pViDecCtxt); pC->pViDecCtxt = M4OSA_NULL; if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_cleanUp: m_pVideoDecoder->pFctDestroy returns 0x%x", err); /**< don't return, we still have stuff to free */ } } /* ----- Free the audio decoder stuff ----- */ if( M4OSA_NULL != pC->pAudioDecCtxt ) { err = pC->m_pAudioDecoder->m_pFctDestroyAudioDec(pC->pAudioDecCtxt); pC->pAudioDecCtxt = M4OSA_NULL; if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_cleanUp: m_pAudioDecoder->m_pFctDestroyAudioDec returns 0x%x", err); /**< don't return, we still have stuff to free */ } } if( M4OSA_NULL != pC->AudioDecBufferOut.m_dataAddress ) { free(pC->AudioDecBufferOut.m_dataAddress); pC->AudioDecBufferOut.m_dataAddress = M4OSA_NULL; } /* ----- Free reader stuff, if needed ----- */ // We cannot free the reader before decoders because the decoders may read // from the reader (in another thread) before being stopped. if( M4OSA_NULL != pC-> pReaderContext ) /**< may be M4OSA_NULL if M4MCS_open was not called */ { err = pC->m_pReader->m_pFctClose(pC->pReaderContext); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1("M4MCS_cleanUp: m_pReader->m_pFctClose returns 0x%x", err); /**< don't return, we still have stuff to free */ } err = pC->m_pReader->m_pFctDestroy(pC->pReaderContext); pC->pReaderContext = M4OSA_NULL; if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_cleanUp: m_pReader->m_pFctDestroy returns 0x%x", err); /**< don't return, we still have stuff to free */ } } if( pC->m_pDataAddress1 != M4OSA_NULL ) { free(pC->m_pDataAddress1); pC->m_pDataAddress1 = M4OSA_NULL; } if( pC->m_pDataAddress2 != M4OSA_NULL ) { free(pC->m_pDataAddress2); pC->m_pDataAddress2 = M4OSA_NULL; } /*Bug fix 11/12/2008 (to obtain more precise video end cut)*/ if( pC->m_pDataVideoAddress1 != M4OSA_NULL ) { free(pC->m_pDataVideoAddress1); pC->m_pDataVideoAddress1 = M4OSA_NULL; } if( pC->m_pDataVideoAddress2 != M4OSA_NULL ) { free(pC->m_pDataVideoAddress2); pC->m_pDataVideoAddress2 = M4OSA_NULL; } return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4MCS_open_normalMode(M4MCS_Context pContext, M4OSA_Void* pFileIn, * M4OSA_Void* pFileOut, M4OSA_Void* pTempFile); * @brief Set the MCS input and output files. It is the same as M4MCS_open without * M4MCS_WITH_FAST_OPEN flag It is used in VideoArtist * @note It opens the input file, but the output file is not created yet. * @param pContext (IN) MCS context * @param pFileIn (IN) Input file to transcode (The type of this parameter * (URL, pipe...) depends on the OSAL implementation). * @param mediaType (IN) Container type (.3gp,.amr, ...) of input file. * @param pFileOut (IN) Output file to create (The type of this parameter * (URL, pipe...) depends on the OSAL implementation). * @param pTempFile (IN) Temporary file for the constant memory writer to store * metadata ("moov.bin"). * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL (debug only) * @return M4ERR_STATE: MCS is not in an appropriate state for this function to be called * @return M4ERR_ALLOC: There is no more available memory * @return M4ERR_FILE_NOT_FOUND: The input file has not been found * @return M4MCS_ERR_INVALID_INPUT_FILE: The input file is not a valid file, or is corrupted * @return M4MCS_ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM: The input file contains no * supported audio or video stream ****************************************************************************** */ M4OSA_ERR M4MCS_open_normalMode(M4MCS_Context pContext, M4OSA_Void* pFileIn, M4VIDEOEDITING_FileType InputFileType, M4OSA_Void* pFileOut, M4OSA_Void* pTempFile) { M4MCS_InternalContext *pC = (M4MCS_InternalContext*)(pContext); M4OSA_ERR err; M4READER_MediaFamily mediaFamily; M4_StreamHandler* pStreamHandler; M4OSA_TRACE2_3("M4MCS_open_normalMode called with pContext=0x%x, pFileIn=0x%x,\ pFileOut=0x%x", pContext, pFileIn, pFileOut); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4MCS_open_normalMode: pContext is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pFileIn) , M4ERR_PARAMETER, "M4MCS_open_normalMode: pFileIn is M4OSA_NULL"); if ((InputFileType == M4VIDEOEDITING_kFileType_JPG) ||(InputFileType == M4VIDEOEDITING_kFileType_PNG) ||(InputFileType == M4VIDEOEDITING_kFileType_GIF) ||(InputFileType == M4VIDEOEDITING_kFileType_BMP)) { M4OSA_TRACE1_0("M4MCS_open_normalMode: Still picture is not\ supported with this function"); return M4MCS_ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM; } /** * Check state automaton */ if (M4MCS_kState_CREATED != pC->State) { M4OSA_TRACE1_1("M4MCS_open_normalMode(): Wrong State (%d), returning M4ERR_STATE", pC->State); return M4ERR_STATE; } /* Copy function input parameters into our context */ pC->pInputFile = pFileIn; pC->InputFileType = InputFileType; pC->pOutputFile = pFileOut; pC->pTemporaryFile = pTempFile; /***********************************/ /* Open input file with the reader */ /***********************************/ err = M4MCS_setCurrentReader(pContext, pC->InputFileType); M4ERR_CHECK_RETURN(err); /** * Reset reader related variables */ pC->VideoState = M4MCS_kStreamState_NOSTREAM; pC->AudioState = M4MCS_kStreamState_NOSTREAM; pC->pReaderVideoStream = M4OSA_NULL; pC->pReaderAudioStream = M4OSA_NULL; /*******************************************************/ /* Initializes the reader shell and open the data file */ /*******************************************************/ err = pC->m_pReader->m_pFctCreate(&pC->pReaderContext); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4MCS_open_normalMode(): m_pReader->m_pFctCreate returns 0x%x", err); return err; } /** * Link the reader interface to the reader context */ pC->m_pReaderDataIt->m_readerContext = pC->pReaderContext; /** * Set the reader shell file access functions */ err = pC->m_pReader->m_pFctSetOption(pC->pReaderContext, M4READER_kOptionID_SetOsaFileReaderFctsPtr, (M4OSA_DataOption)pC->pOsaFileReadPtr); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4MCS_open_normalMode(): m_pReader->m_pFctSetOption returns 0x%x", err); return err; } /** * Open the input file */ err = pC->m_pReader->m_pFctOpen(pC->pReaderContext, pC->pInputFile); if (M4NO_ERROR != err) { M4OSA_UInt32 uiDummy, uiCoreId; M4OSA_TRACE1_1("M4MCS_open_normalMode(): m_pReader->m_pFctOpen returns 0x%x", err); if (err == ((M4OSA_UInt32)M4ERR_UNSUPPORTED_MEDIA_TYPE)) { M4OSA_TRACE1_0("M4MCS_open_normalMode(): returning M4MCS_ERR_FILE_DRM_PROTECTED"); return M4MCS_ERR_FILE_DRM_PROTECTED; } else { /** * If the error is from the core reader, we change it to a public VXS error */ M4OSA_ERR_SPLIT(err, uiDummy, uiCoreId, uiDummy); if (M4MP4_READER == uiCoreId) { M4OSA_TRACE1_0("M4MCS_open_normalMode(): returning M4MCS_ERR_INVALID_INPUT_FILE"); return M4MCS_ERR_INVALID_INPUT_FILE; } } return err; } /** * Get the streams from the input file */ while (M4NO_ERROR == err) { err = pC->m_pReader->m_pFctGetNextStream(pC->pReaderContext, &mediaFamily, &pStreamHandler); /** * In case we found a BIFS stream or something else...*/ if((err == ((M4OSA_UInt32)M4ERR_READER_UNKNOWN_STREAM_TYPE)) || (err == ((M4OSA_UInt32)M4WAR_TOO_MUCH_STREAMS))) { err = M4NO_ERROR; continue; } if (M4NO_ERROR == err) /**< One stream found */ { /** * Found the first video stream */ if ((M4READER_kMediaFamilyVideo == mediaFamily) \ && (M4OSA_NULL == pC->pReaderVideoStream)) { if ((M4DA_StreamTypeVideoH263==pStreamHandler->m_streamType) || (M4DA_StreamTypeVideoMpeg4==pStreamHandler->m_streamType) #ifdef M4VSS_SUPPORT_VIDEO_AVC ||(M4DA_StreamTypeVideoMpeg4Avc==pStreamHandler->m_streamType)) #else ||((M4DA_StreamTypeVideoMpeg4Avc==pStreamHandler->m_streamType) &&(pC->m_pVideoDecoderItTable[M4DECODER_kVideoTypeAVC] != M4OSA_NULL))) #endif { M4OSA_TRACE3_0("M4MCS_open_normalMode():\ Found a H263 or MPEG-4 video stream in input 3gpp clip"); /** * Keep pointer to the video stream */ pC->pReaderVideoStream = (M4_VideoStreamHandler*)pStreamHandler; pC->bUnsupportedVideoFound = M4OSA_FALSE; pStreamHandler->m_bStreamIsOK = M4OSA_TRUE; /** * Init our video stream state variable */ pC->VideoState = M4MCS_kStreamState_STARTED; /** * Reset the stream reader */ err = pC->m_pReader->m_pFctReset(pC->pReaderContext, (M4_StreamHandler*)pC->pReaderVideoStream); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4MCS_open_normalMode():\ m_pReader->m_pFctReset(video) returns 0x%x", err); return err; } /** * Initializes an access Unit */ err = pC->m_pReader->m_pFctFillAuStruct(pC->pReaderContext, pStreamHandler, &pC->ReaderVideoAU); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4MCS_open_normalMode():\ m_pReader->m_pFctFillAuStruct(video) returns 0x%x", err); return err; } } else /**< Not H263 or MPEG-4 (H264, etc.) */ { M4OSA_TRACE1_1("M4MCS_open_normalMode():\ Found an unsupported video stream (0x%x) in input 3gpp clip", pStreamHandler->m_streamType); pC->bUnsupportedVideoFound = M4OSA_TRUE; pStreamHandler->m_bStreamIsOK = M4OSA_FALSE; } } /** * Found the first audio stream */ else if ((M4READER_kMediaFamilyAudio == mediaFamily) && (M4OSA_NULL == pC->pReaderAudioStream)) { if ((M4DA_StreamTypeAudioAmrNarrowBand==pStreamHandler->m_streamType) || (M4DA_StreamTypeAudioAac==pStreamHandler->m_streamType) || (M4DA_StreamTypeAudioMp3==pStreamHandler->m_streamType) || (M4DA_StreamTypeAudioEvrc==pStreamHandler->m_streamType) ) { M4OSA_TRACE3_0("M4MCS_open_normalMode(): Found an AMR-NB, AAC \ or MP3 audio stream in input clip"); /** * Keep pointer to the audio stream */ pC->pReaderAudioStream = (M4_AudioStreamHandler*)pStreamHandler; pStreamHandler->m_bStreamIsOK = M4OSA_TRUE; pC->bUnsupportedAudioFound = M4OSA_FALSE; /** * Init our audio stream state variable */ pC->AudioState = M4MCS_kStreamState_STARTED; /** * Reset the stream reader */ err = pC->m_pReader->m_pFctReset(pC->pReaderContext, (M4_StreamHandler*)pC->pReaderAudioStream); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4MCS_open_normalMode():\ m_pReader->m_pFctReset(audio) returns 0x%x", err); return err; } /** * Initializes an access Unit */ err = pC->m_pReader->m_pFctFillAuStruct(pC->pReaderContext, pStreamHandler, &pC->ReaderAudioAU); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4MCS_open_normalMode(): \ m_pReader->m_pFctFillAuStruct(audio) returns 0x%x", err); return err; } /** * Output max AU size is equal to input max AU size (this value * will be changed if there is audio transcoding) */ pC->uiAudioMaxAuSize = pStreamHandler->m_maxAUSize; } else { /**< Not AMR-NB, AAC, MP3 nor EVRC (AMR-WB, WAV...) */ M4OSA_TRACE1_1("M4MCS_open_normalMode(): Found an unsupported audio stream\ (0x%x) in input 3gpp clip", pStreamHandler->m_streamType); pC->bUnsupportedAudioFound = M4OSA_TRUE; pStreamHandler->m_bStreamIsOK = M4OSA_FALSE; } } } } /**< end of while (M4NO_ERROR == err) */ /** * Check we found at least one supported stream */ if((M4OSA_NULL == pC->pReaderVideoStream) && (M4OSA_NULL == pC->pReaderAudioStream)) { M4OSA_TRACE1_0("M4MCS_open_normalMode(): returning \ M4MCS_ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM"); return M4MCS_ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM; } #ifndef M4VSS_ENABLE_EXTERNAL_DECODERS if(pC->VideoState == M4MCS_kStreamState_STARTED) { err = M4MCS_setCurrentVideoDecoder(pContext, pC->pReaderVideoStream->m_basicProperties.m_streamType); M4ERR_CHECK_RETURN(err); } #endif if(pC->AudioState == M4MCS_kStreamState_STARTED) { //EVRC if(M4DA_StreamTypeAudioEvrc != pStreamHandler->m_streamType) /* decoder not supported yet, but allow to do null encoding */ { err = M4MCS_setCurrentAudioDecoder(pContext, pC->pReaderAudioStream->m_basicProperties.m_streamType); M4ERR_CHECK_RETURN(err); } } /** * Get the audio and video stream properties */ err = M4MCS_intGetInputClipProperties(pC); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4MCS_open_normalMode():\ M4MCS_intGetInputClipProperties returns 0x%x", err); return err; } /** * Set the begin cut decoding increment according to the input frame rate */ if (0. != pC->InputFileProperties.fAverageFrameRate) /**< sanity check */ { pC->iVideoBeginDecIncr = (M4OSA_Int32)(3000. \ / pC->InputFileProperties.fAverageFrameRate); /**< about 3 frames */ } else { pC->iVideoBeginDecIncr = 200; /**< default value: 200 milliseconds (3 frames @ 15fps)*/ } /** * Update state automaton */ pC->State = M4MCS_kState_OPENED; /** * Return with no error */ M4OSA_TRACE3_0("M4MCS_open_normalMode(): returning M4NO_ERROR"); return M4NO_ERROR; } M4OSA_ERR M4MCS_intCheckAndGetCodecProperties( M4MCS_InternalContext *pC) { M4OSA_ERR err = M4NO_ERROR; M4AD_Buffer outputBuffer; uint32_t optionValue =0; M4OSA_TRACE3_0("M4MCS_intCheckAndGetCodecProperties :start"); // Decode first audio frame from clip to get properties from codec if (M4DA_StreamTypeAudioAac == pC->pReaderAudioStream->m_basicProperties.m_streamType) { err = pC->m_pAudioDecoder->m_pFctCreateAudioDec( &pC->pAudioDecCtxt, pC->pReaderAudioStream, &(pC->AacProperties)); } else { err = pC->m_pAudioDecoder->m_pFctCreateAudioDec( &pC->pAudioDecCtxt, pC->pReaderAudioStream, pC->m_pCurrentAudioDecoderUserData); } if (M4NO_ERROR != err) { M4OSA_TRACE1_1( "M4MCS_intCheckAndGetCodecProperties: m_pFctCreateAudioDec \ returns 0x%x", err); return err; } pC->m_pAudioDecoder->m_pFctSetOptionAudioDec(pC->pAudioDecCtxt, M4AD_kOptionID_3gpReaderInterface, (M4OSA_DataOption) pC->m_pReaderDataIt); pC->m_pAudioDecoder->m_pFctSetOptionAudioDec(pC->pAudioDecCtxt, M4AD_kOptionID_AudioAU, (M4OSA_DataOption) &pC->ReaderAudioAU); if( pC->m_pAudioDecoder->m_pFctStartAudioDec != M4OSA_NULL ) { err = pC->m_pAudioDecoder->m_pFctStartAudioDec(pC->pAudioDecCtxt); if( M4NO_ERROR != err ) { M4OSA_TRACE1_1( "M4MCS_intCheckAndGetCodecProperties: m_pFctStartAudioDec \ returns 0x%x", err); return err; } } /** * Allocate output buffer for the audio decoder */ outputBuffer.m_bufferSize = pC->pReaderAudioStream->m_byteFrameLength * pC->pReaderAudioStream->m_byteSampleSize * pC->pReaderAudioStream->m_nbChannels; if( outputBuffer.m_bufferSize > 0 ) { outputBuffer.m_dataAddress = (M4OSA_MemAddr8)M4OSA_32bitAlignedMalloc(outputBuffer.m_bufferSize \ *sizeof(short), M4MCS, (M4OSA_Char *)"outputBuffer.m_bufferSize"); if( M4OSA_NULL == outputBuffer.m_dataAddress ) { M4OSA_TRACE1_0( "M4MCS_intCheckAndGetCodecProperties():\ unable to allocate outputBuffer.m_dataAddress, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } } err = pC->m_pAudioDecoder->m_pFctStepAudioDec(pC->pAudioDecCtxt, M4OSA_NULL, &outputBuffer, M4OSA_FALSE); if ( err == M4WAR_INFO_FORMAT_CHANGE ) { // Get the properties from codec node pC->m_pAudioDecoder->m_pFctGetOptionAudioDec(pC->pAudioDecCtxt, M4AD_kOptionID_AudioNbChannels, (M4OSA_DataOption) &optionValue); // Reset Reader structure value also pC->pReaderAudioStream->m_nbChannels = optionValue; pC->m_pAudioDecoder->m_pFctGetOptionAudioDec(pC->pAudioDecCtxt, M4AD_kOptionID_AudioSampFrequency, (M4OSA_DataOption) &optionValue); // Reset Reader structure value also pC->pReaderAudioStream->m_samplingFrequency = optionValue; if (M4DA_StreamTypeAudioAac == pC->pReaderAudioStream->m_basicProperties.m_streamType) { pC->AacProperties.aNumChan = pC->pReaderAudioStream->m_nbChannels; pC->AacProperties.aSampFreq = pC->pReaderAudioStream->m_samplingFrequency; } } else if( err != M4NO_ERROR) { M4OSA_TRACE1_1("M4MCS_intCheckAndGetCodecProperties:\ m_pFctStepAudioDec returns err = 0x%x", err); } free(outputBuffer.m_dataAddress); // Reset the stream reader err = pC->m_pReader->m_pFctReset(pC->pReaderContext, (M4_StreamHandler *)pC->pReaderAudioStream); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4MCS_intCheckAndGetCodecProperties\ Error in reseting reader: 0x%x", err); } return err; } M4OSA_ERR M4MCS_intLimitBitratePerCodecProfileLevel( M4ENCODER_AdvancedParams* EncParams) { M4OSA_ERR err = M4NO_ERROR; switch (EncParams->Format) { case M4ENCODER_kH263: EncParams->Bitrate = M4MCS_intLimitBitrateForH263Enc( EncParams->videoProfile, EncParams->videoLevel, EncParams->Bitrate); break; case M4ENCODER_kMPEG4: EncParams->Bitrate = M4MCS_intLimitBitrateForMpeg4Enc( EncParams->videoProfile, EncParams->videoLevel, EncParams->Bitrate); break; case M4ENCODER_kH264: EncParams->Bitrate = M4MCS_intLimitBitrateForH264Enc( EncParams->videoProfile, EncParams->videoLevel, EncParams->Bitrate); break; default: M4OSA_TRACE1_1("M4MCS_intLimitBitratePerCodecProfileLevel: \ Wrong enc format %d", EncParams->Format); err = M4ERR_PARAMETER; break; } return err; } M4OSA_Int32 M4MCS_intLimitBitrateForH264Enc(M4OSA_Int32 profile, M4OSA_Int32 level, M4OSA_Int32 bitrate) { M4OSA_Int32 vidBitrate = 0; switch (profile) { case OMX_VIDEO_AVCProfileBaseline: case OMX_VIDEO_AVCProfileMain: switch (level) { case OMX_VIDEO_AVCLevel1: vidBitrate = (bitrate > 64000) ? 64000 : bitrate; break; case OMX_VIDEO_AVCLevel1b: vidBitrate = (bitrate > 128000) ? 128000 : bitrate; break; case OMX_VIDEO_AVCLevel11: vidBitrate = (bitrate > 192000) ? 192000 : bitrate; break; case OMX_VIDEO_AVCLevel12: vidBitrate = (bitrate > 384000) ? 384000 : bitrate; break; case OMX_VIDEO_AVCLevel13: vidBitrate = (bitrate > 768000) ? 768000 : bitrate; break; case OMX_VIDEO_AVCLevel2: vidBitrate = (bitrate > 2000000) ? 2000000 : bitrate; break; case OMX_VIDEO_AVCLevel21: vidBitrate = (bitrate > 4000000) ? 4000000 : bitrate; break; case OMX_VIDEO_AVCLevel22: vidBitrate = (bitrate > 4000000) ? 4000000 : bitrate; break; case OMX_VIDEO_AVCLevel3: vidBitrate = (bitrate > 10000000) ? 10000000 : bitrate; break; case OMX_VIDEO_AVCLevel31: vidBitrate = (bitrate > 14000000) ? 14000000 : bitrate; break; case OMX_VIDEO_AVCLevel32: vidBitrate = (bitrate > 20000000) ? 20000000 : bitrate; break; case OMX_VIDEO_AVCLevel4: vidBitrate = (bitrate > 20000000) ? 20000000 : bitrate; break; case OMX_VIDEO_AVCLevel41: vidBitrate = (bitrate > 50000000) ? 50000000 : bitrate; break; case OMX_VIDEO_AVCLevel42: vidBitrate = (bitrate > 50000000) ? 50000000 : bitrate; break; case OMX_VIDEO_AVCLevel5: vidBitrate = (bitrate > 135000000) ? 135000000 : bitrate; break; case OMX_VIDEO_AVCLevel51: vidBitrate = (bitrate > 240000000) ? 240000000 : bitrate; break; default: vidBitrate = bitrate; break; } break; case OMX_VIDEO_AVCProfileHigh: switch (level) { case OMX_VIDEO_AVCLevel1: vidBitrate = (bitrate > 80000) ? 80000 : bitrate; break; case OMX_VIDEO_AVCLevel1b: vidBitrate = (bitrate > 160000) ? 160000 : bitrate; break; case OMX_VIDEO_AVCLevel11: vidBitrate = (bitrate > 240000) ? 240000 : bitrate; break; case OMX_VIDEO_AVCLevel12: vidBitrate = (bitrate > 480000) ? 480000 : bitrate; break; case OMX_VIDEO_AVCLevel13: vidBitrate = (bitrate > 960000) ? 960000 : bitrate; break; case OMX_VIDEO_AVCLevel2: vidBitrate = (bitrate > 2500000) ? 2500000 : bitrate; break; case OMX_VIDEO_AVCLevel21: vidBitrate = (bitrate > 5000000) ? 5000000 : bitrate; break; case OMX_VIDEO_AVCLevel22: vidBitrate = (bitrate > 5000000) ? 5000000 : bitrate; break; case OMX_VIDEO_AVCLevel3: vidBitrate = (bitrate > 12500000) ? 12500000 : bitrate; break; case OMX_VIDEO_AVCLevel31: vidBitrate = (bitrate > 17500000) ? 17500000 : bitrate; break; case OMX_VIDEO_AVCLevel32: vidBitrate = (bitrate > 25000000) ? 25000000 : bitrate; break; case OMX_VIDEO_AVCLevel4: vidBitrate = (bitrate > 25000000) ? 25000000 : bitrate; break; case OMX_VIDEO_AVCLevel41: vidBitrate = (bitrate > 62500000) ? 62500000 : bitrate; break; case OMX_VIDEO_AVCLevel42: vidBitrate = (bitrate > 62500000) ? 62500000 : bitrate; break; case OMX_VIDEO_AVCLevel5: vidBitrate = (bitrate > 168750000) ? 168750000 : bitrate; break; case OMX_VIDEO_AVCLevel51: vidBitrate = (bitrate > 300000000) ? 300000000 : bitrate; break; default: vidBitrate = bitrate; break; } break; default: // We do not handle any other AVC profile for now. // Return input bitrate vidBitrate = bitrate; break; } return vidBitrate; } M4OSA_Int32 M4MCS_intLimitBitrateForMpeg4Enc(M4OSA_Int32 profile, M4OSA_Int32 level, M4OSA_Int32 bitrate) { M4OSA_Int32 vidBitrate = 0; switch (profile) { case OMX_VIDEO_MPEG4ProfileSimple: switch (level) { case OMX_VIDEO_MPEG4Level0: vidBitrate = (bitrate > 64000) ? 64000 : bitrate; break; case OMX_VIDEO_MPEG4Level0b: vidBitrate = (bitrate > 128000) ? 128000 : bitrate; break; case OMX_VIDEO_MPEG4Level1: vidBitrate = (bitrate > 64000) ? 64000 : bitrate; break; case OMX_VIDEO_MPEG4Level2: vidBitrate = (bitrate > 128000) ? 128000 : bitrate; break; case OMX_VIDEO_MPEG4Level3: vidBitrate = (bitrate > 384000) ? 384000 : bitrate; break; default: vidBitrate = bitrate; break; } break; default: // We do not handle any other MPEG4 profile for now. // Return input bitrate vidBitrate = bitrate; break; } return vidBitrate; } M4OSA_Int32 M4MCS_intLimitBitrateForH263Enc(M4OSA_Int32 profile, M4OSA_Int32 level, M4OSA_Int32 bitrate) { M4OSA_Int32 vidBitrate = 0; switch (profile) { case OMX_VIDEO_H263ProfileBaseline: switch (level) { case OMX_VIDEO_H263Level10: vidBitrate = (bitrate > 64000) ? 64000 : bitrate; break; case OMX_VIDEO_H263Level20: vidBitrate = (bitrate > 128000) ? 128000 : bitrate; break; case OMX_VIDEO_H263Level30: vidBitrate = (bitrate > 384000) ? 384000 : bitrate; break; default: vidBitrate = bitrate; break; } break; default: // We do not handle any other H263 profile for now. // Return input bitrate vidBitrate = bitrate; break; } return vidBitrate; }