| /* |
| * 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"); |
| |
| instance->m_Num_Bytes_NALUnitLength = |
| (instance->m_pDecoderSpecificInfo[4] & 0x03) + 1; |
| |
| 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; |
| } |
| |
| if (nal_size == 0) { |
| M4OSA_TRACE1_1("0 size nal unit at line %d", __LINE__); |
| frame_size += instance->m_Num_Bytes_NALUnitLength; |
| continue; |
| } |
| |
| 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; |
| } |