/* * 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 M4PTO3GPP_API.c * @brief Picture to 3gpp Service implementation. * @note ****************************************************************************** */ /*16 bytes signature to be written in the generated 3gp files */ #define M4PTO3GPP_SIGNATURE "NXP-SW : PTO3GPP" /****************/ /*** Includes ***/ /****************/ /** * Our header */ #include "M4PTO3GPP_InternalTypes.h" #include "M4PTO3GPP_API.h" /** * Our errors */ #include "M4PTO3GPP_ErrorCodes.h" #ifdef M4VSS_SUPPORT_ENCODER_MPEG4 #include "VideoEditorVideoEncoder.h" #endif /** * OSAL headers */ #include "M4OSA_Memory.h" /* OSAL memory management */ #include "M4OSA_Debug.h" /* OSAL debug management */ /************************/ /*** Various Magicals ***/ /************************/ #define M4PTO3GPP_WRITER_AUDIO_STREAM_ID 1 #define M4PTO3GPP_WRITER_VIDEO_STREAM_ID 2 #define M4PTO3GPP_QUANTIZER_STEP 4 /**< Quantizer step */ #define M4PTO3GPP_WRITER_AUDIO_PROFILE_LEVEL 0xFF /**< No specific profile and level */ #define M4PTO3GPP_WRITER_AUDIO_AMR_TIME_SCALE 8000 /**< AMR */ #define M4PTO3GPP_BITRATE_REGULATION_CTS_PERIOD_IN_MS 500 /**< MAGICAL */ #define M4PTO3GPP_MARGE_OF_FILE_SIZE 25000 /**< MAGICAL */ /** ****************************************************************************** * define AMR 12.2 kbps silence frame ****************************************************************************** */ #define M4PTO3GPP_AMR_AU_SILENCE_FRAME_122_SIZE 32 #define M4PTO3GPP_AMR_AU_SILENCE_FRAME_122_DURATION 20 const M4OSA_UInt8 M4PTO3GPP_AMR_AU_SILENCE_122_FRAME[M4PTO3GPP_AMR_AU_SILENCE_FRAME_122_SIZE]= { 0x3C, 0x91, 0x17, 0x16, 0xBE, 0x66, 0x78, 0x00, 0x00, 0x01, 0xE7, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #define M4PTO3GPP_AMR_AU_SILENCE_FRAME_048_SIZE 13 #define M4PTO3GPP_AMR_AU_SILENCE_FRAME_048_DURATION 20 const M4OSA_UInt8 M4PTO3GPP_AMR_AU_SILENCE_048_FRAME[M4PTO3GPP_AMR_AU_SILENCE_FRAME_048_SIZE] = { 0x04, 0xFF, 0x18, 0xC7, 0xF0, 0x0D, 0x04, 0x33, 0xFF, 0xE0, 0x00, 0x00, 0x00 }; /***************************/ /*** "Private" functions ***/ /***************************/ static M4OSA_ERR M4PTO3GPP_Ready4Processing(M4PTO3GPP_InternalContext* pC); /****************************/ /*** "External" functions ***/ /****************************/ extern M4OSA_ERR M4WRITER_3GP_getInterfaces(M4WRITER_OutputFileType* pType, M4WRITER_GlobalInterface** SrcGlobalInterface, M4WRITER_DataInterface** SrcDataInterface); extern M4OSA_ERR M4READER_AMR_getInterfaces(M4READER_MediaType *pMediaType, M4READER_GlobalInterface **pRdrGlobalInterface, M4READER_DataInterface **pRdrDataInterface); extern M4OSA_ERR M4READER_3GP_getInterfaces(M4READER_MediaType *pMediaType, M4READER_GlobalInterface **pRdrGlobalInterface, M4READER_DataInterface **pRdrDataInterface); /****************************/ /*** "Static" functions ***/ /****************************/ static M4OSA_ERR M4PTO3GPP_writeAmrSilence122Frame( M4WRITER_DataInterface* pWriterDataIntInterface, M4WRITER_Context* pWriterContext, M4SYS_AccessUnit* pWriterAudioAU, M4OSA_Time mtIncCts); static M4OSA_ERR M4PTO3GPP_writeAmrSilence048Frame( M4WRITER_DataInterface* pWriterDataIntInterface, M4WRITER_Context* pWriterContext, M4SYS_AccessUnit* pWriterAudioAU, M4OSA_Time mtIncCts); /** ****************************************************************************** * M4OSA_ERR M4PTO3GPP_GetVersion(M4_VersionInfo* pVersionInfo); * @brief Get the M4PTO3GPP 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 M4PTO3GPP_GetVersion(M4_VersionInfo* pVersionInfo) /*********************************************************/ { M4OSA_TRACE3_1("M4PTO3GPP_GetVersion called with pVersionInfo=0x%x", pVersionInfo); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL==pVersionInfo),M4ERR_PARAMETER, "M4PTO3GPP_GetVersion: pVersionInfo is M4OSA_NULL"); pVersionInfo->m_major = M4PTO3GPP_VERSION_MAJOR; pVersionInfo->m_minor = M4PTO3GPP_VERSION_MINOR; pVersionInfo->m_revision = M4PTO3GPP_VERSION_REVISION; return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4PTO3GPP_Init(M4PTO3GPP_Context* pContext); * @brief Initializes the M4PTO3GPP (allocates an execution context). * @note * @param pContext (OUT) Pointer on the M4PTO3GPP 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 M4PTO3GPP_Init( M4PTO3GPP_Context* pContext, M4OSA_FileReadPointer* pFileReadPtrFct, M4OSA_FileWriterPointer* pFileWritePtrFct) /*********************************************************/ { M4PTO3GPP_InternalContext *pC; M4OSA_UInt32 i; M4OSA_TRACE3_1("M4PTO3GPP_Init called with pContext=0x%x", pContext); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, "M4PTO3GPP_Init: pContext is M4OSA_NULL"); /** * Allocate the M4PTO3GPP context and return it to the user */ pC = (M4PTO3GPP_InternalContext*)M4OSA_32bitAlignedMalloc(sizeof(M4PTO3GPP_InternalContext), M4PTO3GPP, (M4OSA_Char *)"M4PTO3GPP_InternalContext"); *pContext = pC; if (M4OSA_NULL == pC) { M4OSA_TRACE1_0("M4PTO3GPP_Step(): unable to allocate M4PTO3GPP_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->m_State = M4PTO3GPP_kState_CREATED; pC->m_VideoState = M4PTO3GPP_kStreamState_NOSTREAM; pC->m_AudioState = M4PTO3GPP_kStreamState_NOSTREAM; /** * Reader stuff */ pC->m_pReaderAudioAU = M4OSA_NULL; pC->m_pReaderAudioStream = M4OSA_NULL; /** * Writer stuff */ pC->m_pEncoderHeader = M4OSA_NULL; pC->m_pWriterVideoStream = M4OSA_NULL; pC->m_pWriterAudioStream = M4OSA_NULL; pC->m_pWriterVideoStreamInfo= M4OSA_NULL; pC->m_pWriterAudioStreamInfo= M4OSA_NULL; /** * Contexts of the used modules */ pC->m_pAudioReaderContext = M4OSA_NULL; pC->m_p3gpWriterContext = M4OSA_NULL; pC->m_pMp4EncoderContext = M4OSA_NULL; pC->m_eEncoderState = M4PTO3GPP_kNoEncoder; /** * Interfaces of the used modules */ pC->m_pReaderGlobInt = M4OSA_NULL; pC->m_pReaderDataInt = M4OSA_NULL; pC->m_pWriterGlobInt = M4OSA_NULL; pC->m_pWriterDataInt = M4OSA_NULL; pC->m_pEncoderInt = M4OSA_NULL; pC->m_pEncoderExternalAPI = M4OSA_NULL; pC->m_pEncoderUserData = M4OSA_NULL; /** * Fill the OSAL file function set */ pC->pOsalFileRead = pFileReadPtrFct; pC->pOsalFileWrite = pFileWritePtrFct; /** * Video rate control stuff */ pC->m_mtCts = 0.0F; pC->m_mtNextCts = 0.0F; pC->m_mtAudioCts = 0.0F; pC->m_AudioOffSet = 0.0F; pC->m_dLastVideoRegulCts= 0.0F; pC->m_PrevAudioCts = 0.0F; pC->m_DeltaAudioCts = 0.0F; pC->m_MaxFileSize = 0; pC->m_CurrentFileSize = 0; pC->m_IsLastPicture = M4OSA_FALSE; pC->m_bAudioPaddingSilence = M4OSA_FALSE; pC->m_bLastInternalCallBack = M4OSA_FALSE; pC->m_NbCurrentFrame = 0; pC->pSavedPlane = M4OSA_NULL; pC->uiSavedDuration = 0; M4OSA_TRACE3_0("M4PTO3GPP_Init(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4PTO3GPP_Open(M4PTO3GPP_Context pContext, M4PTO3GPP_Params* pParams); * @brief Set the M4PTO3GPP input and output files. * @note It opens the input file, but the output file may not be created yet. * @param pContext (IN) M4PTO3GPP context * @param pParams (IN) Pointer to the parameters for the PTO3GPP. * @note The pointed structure can be de-allocated after this function returns because * it is internally copied by the PTO3GPP * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL * @return M4ERR_STATE: M4PTO3GPP is not in an appropriate state for this function to be called * @return M4ERR_ALLOC: There is no more available memory * @return ERR_PTO3GPP_INVALID_VIDEO_FRAME_SIZE_FOR_H263 The output video frame * size parameter is incompatible with H263 encoding * @return ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_FORMAT The output video format parameter is undefined * @return ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_BITRATE The output video bit-rate parameter is undefined * @return ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE The output video frame size parameter is undefined * @return ERR_PTO3GPP_UNDEFINED_OUTPUT_FILE_SIZE The output file size parameter is undefined * @return ERR_PTO3GPP_UNDEFINED_AUDIO_PADDING The output audio padding parameter is undefined * @return ERR_PTO3GPP_UNHANDLED_AUDIO_TRACK_INPUT_FILE The input audio file contains a track format not handled by PTO3GPP ****************************************************************************** */ /*********************************************************/ M4OSA_ERR M4PTO3GPP_Open(M4PTO3GPP_Context pContext, M4PTO3GPP_Params* pParams) /*********************************************************/ { M4PTO3GPP_InternalContext *pC = (M4PTO3GPP_InternalContext*)(pContext); M4OSA_ERR err = M4NO_ERROR; M4READER_MediaFamily mediaFamily; M4_StreamHandler* pStreamHandler; M4READER_MediaType readerMediaType; M4OSA_TRACE2_2("M4PTO3GPP_Open called with pContext=0x%x, pParams=0x%x", pContext, pParams); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL == pContext), M4ERR_PARAMETER, \ "M4PTO3GPP_Open: pContext is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pParams), M4ERR_PARAMETER, \ "M4PTO3GPP_Open: pParams is M4OSA_NULL"); /** * Check parameters correctness */ M4OSA_DEBUG_IF2((M4OSA_NULL == pParams->pPictureCallbackFct), M4ERR_PARAMETER, "M4PTO3GPP_Open: pC->m_Params.pPictureCallbackFct is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pParams->pPictureCallbackCtxt), M4ERR_PARAMETER, "M4PTO3GPP_Open: pC->m_Params.pPictureCallbackCtxt is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pParams->pOutput3gppFile), M4ERR_PARAMETER, "M4PTO3GPP_Open: pC->m_Params.pOutput3gppFile is M4OSA_NULL"); M4OSA_DEBUG_IF2((M4OSA_NULL == pParams->pTemporaryFile), M4ERR_PARAMETER, "M4PTO3GPP_Open: pC->m_Params.pTemporaryFile is M4OSA_NULL"); /** * Video Format */ if( (M4VIDEOEDITING_kH263 != pParams->OutputVideoFormat) && (M4VIDEOEDITING_kMPEG4 != pParams->OutputVideoFormat) && (M4VIDEOEDITING_kH264 != pParams->OutputVideoFormat)) { M4OSA_TRACE1_0("M4PTO3GPP_Open: Undefined output video format"); return ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_FORMAT; } /** * Video Bitrate */ if(!((M4VIDEOEDITING_k16_KBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k24_KBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k32_KBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k48_KBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k64_KBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k96_KBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k128_KBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k192_KBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k256_KBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k288_KBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k384_KBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k512_KBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k800_KBPS == pParams->OutputVideoBitrate) || /*+ New Encoder bitrates */ (M4VIDEOEDITING_k2_MBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k5_MBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_k8_MBPS == pParams->OutputVideoBitrate) || (M4VIDEOEDITING_kVARIABLE_KBPS == pParams->OutputVideoBitrate))) { M4OSA_TRACE1_0("M4PTO3GPP_Open: Undefined output video bitrate"); return ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_BITRATE; } /** * Video frame size */ if (!((M4VIDEOEDITING_kSQCIF == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_kQQVGA == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_kQCIF == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_kQVGA == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_kCIF == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_kVGA == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_kNTSC == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_kWVGA == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_k640_360 == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_k854_480 == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_k1280_720 == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_k1080_720 == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_k960_720 == pParams->OutputVideoFrameSize) || (M4VIDEOEDITING_k1920_1080 == pParams->OutputVideoFrameSize))) { M4OSA_TRACE1_0("M4PTO3GPP_Open: Undefined output video frame size"); return ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE; } /** * Maximum size of the output 3GPP file */ if (!((M4PTO3GPP_k50_KB == pParams->OutputFileMaxSize) || (M4PTO3GPP_k75_KB == pParams->OutputFileMaxSize) || (M4PTO3GPP_k100_KB == pParams->OutputFileMaxSize) || (M4PTO3GPP_k150_KB == pParams->OutputFileMaxSize) || (M4PTO3GPP_k200_KB == pParams->OutputFileMaxSize) || (M4PTO3GPP_k300_KB == pParams->OutputFileMaxSize) || (M4PTO3GPP_k400_KB == pParams->OutputFileMaxSize) || (M4PTO3GPP_k500_KB == pParams->OutputFileMaxSize) || (M4PTO3GPP_kUNLIMITED == pParams->OutputFileMaxSize))) { M4OSA_TRACE1_0("M4PTO3GPP_Open: Undefined output 3GPP file size"); return ERR_PTO3GPP_UNDEFINED_OUTPUT_FILE_SIZE; } /* Audio padding */ if (M4OSA_NULL != pParams->pInputAudioTrackFile) { if ((!( (M4PTO3GPP_kAudioPaddingMode_None == pParams->AudioPaddingMode) || (M4PTO3GPP_kAudioPaddingMode_Silence== pParams->AudioPaddingMode) || (M4PTO3GPP_kAudioPaddingMode_Loop == pParams->AudioPaddingMode)))) { M4OSA_TRACE1_0("M4PTO3GPP_Open: Undefined audio padding"); return ERR_PTO3GPP_UNDEFINED_AUDIO_PADDING; } } /**< Size check for H263 (only valid sizes are CIF, QCIF and SQCIF) */ if ((M4VIDEOEDITING_kH263 == pParams->OutputVideoFormat) && (M4VIDEOEDITING_kSQCIF != pParams->OutputVideoFrameSize) && (M4VIDEOEDITING_kQCIF != pParams->OutputVideoFrameSize) && (M4VIDEOEDITING_kCIF != pParams->OutputVideoFrameSize)) { M4OSA_TRACE1_0("M4PTO3GPP_Open():\ returning ERR_PTO3GPP_INVALID_VIDEO_FRAME_SIZE_FOR_H263"); return ERR_PTO3GPP_INVALID_VIDEO_FRAME_SIZE_FOR_H263; } /** * Check state automaton */ if (M4PTO3GPP_kState_CREATED != pC->m_State) { M4OSA_TRACE1_1("M4PTO3GPP_Open(): Wrong State (%d), returning M4ERR_STATE", pC->m_State); return M4ERR_STATE; } /** * Copy the M4PTO3GPP_Params structure */ memcpy((void *)(&pC->m_Params), (void *)pParams, sizeof(M4PTO3GPP_Params)); M4OSA_TRACE1_1("M4PTO3GPP_Open: outputVideoBitrate = %d", pC->m_Params.OutputVideoBitrate); /***********************************/ /* Open input file with the reader */ /***********************************/ if (M4OSA_NULL != pC->m_Params.pInputAudioTrackFile) { /** * Get the reader interface according to the input audio file type */ switch(pC->m_Params.AudioFileFormat) { #ifdef M4VSS_SUPPORT_READER_AMR case M4VIDEOEDITING_kFileType_AMR: err = M4READER_AMR_getInterfaces( &readerMediaType, &pC->m_pReaderGlobInt, &pC->m_pReaderDataInt); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Open(): M4READER_AMR_getInterfaces returns 0x%x", err); return err; } break; #endif #ifdef AAC_SUPPORTED case M4VIDEOEDITING_kFileType_3GPP: err = M4READER_3GP_getInterfaces( &readerMediaType, &pC->m_pReaderGlobInt, &pC->m_pReaderDataInt); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Open(): M4READER_3GP_getInterfaces returns 0x%x", err); return err; } break; #endif default: return ERR_PTO3GPP_UNHANDLED_AUDIO_TRACK_INPUT_FILE; } /** * Initializes the reader shell */ err = pC->m_pReaderGlobInt->m_pFctCreate(&pC->m_pAudioReaderContext); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Open(): pReaderGlobInt->m_pFctCreate returns 0x%x", err); return err; } pC->m_pReaderDataInt->m_readerContext = pC->m_pAudioReaderContext; /**< Link the reader interface to the reader context */ /** * Set the reader shell file access functions */ err = pC->m_pReaderGlobInt->m_pFctSetOption(pC->m_pAudioReaderContext, M4READER_kOptionID_SetOsaFileReaderFctsPtr, (M4OSA_DataOption)pC->pOsalFileRead); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Open(): pReaderGlobInt->m_pFctSetOption returns 0x%x", err); return err; } /** * Open the input audio file */ err = pC->m_pReaderGlobInt->m_pFctOpen(pC->m_pAudioReaderContext, pC->m_Params.pInputAudioTrackFile); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Open(): pReaderGlobInt->m_pFctOpen returns 0x%x", err); pC->m_pReaderGlobInt->m_pFctDestroy(pC->m_pAudioReaderContext); pC->m_pAudioReaderContext = M4OSA_NULL; return err; } /** * Get the audio streams from the input file */ err = M4NO_ERROR; while (M4NO_ERROR == err) { err = pC->m_pReaderGlobInt->m_pFctGetNextStream(pC->m_pAudioReaderContext, &mediaFamily, &pStreamHandler); 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 an audio stream */ if ((M4READER_kMediaFamilyAudio == mediaFamily) && (M4OSA_NULL == pC->m_pReaderAudioStream)) { pC->m_pReaderAudioStream = (M4_AudioStreamHandler*)pStreamHandler; /**< Keep pointer to the audio stream */ M4OSA_TRACE3_0("M4PTO3GPP_Open(): Found an audio stream in input"); pStreamHandler->m_bStreamIsOK = M4OSA_TRUE; /** * Allocate audio AU used for read operations */ pC->m_pReaderAudioAU = (M4_AccessUnit*)M4OSA_32bitAlignedMalloc(sizeof(M4_AccessUnit), M4PTO3GPP,(M4OSA_Char *)"pReaderAudioAU"); if (M4OSA_NULL == pC->m_pReaderAudioAU) { M4OSA_TRACE1_0("M4PTO3GPP_Open(): unable to allocate pReaderAudioAU, \ returning M4ERR_ALLOC"); return M4ERR_ALLOC; } /** * Initializes an access Unit */ err = pC->m_pReaderGlobInt->m_pFctFillAuStruct(pC->m_pAudioReaderContext, pStreamHandler, pC->m_pReaderAudioAU); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Open():\ pReaderGlobInt->m_pFctFillAuStruct(audio)returns 0x%x", err); return err; } } else { pStreamHandler->m_bStreamIsOK = M4OSA_FALSE; } } else if (M4WAR_NO_MORE_STREAM != err) /**< Unexpected error code */ { M4OSA_TRACE1_1("M4PTO3GPP_Open():\ pReaderGlobInt->m_pFctGetNextStream returns 0x%x", err); return err; } } /* while*/ } /*if (M4OSA_NULL != pC->m_Params.pInputAudioTrackFile)*/ pC->m_VideoState = M4PTO3GPP_kStreamState_STARTED; /** * Init the audio stream */ if (M4OSA_NULL != pC->m_pReaderAudioStream) { pC->m_AudioState = M4PTO3GPP_kStreamState_STARTED; err = pC->m_pReaderGlobInt->m_pFctReset(pC->m_pAudioReaderContext, (M4_StreamHandler*)pC->m_pReaderAudioStream); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Open(): pReaderDataInt->m_pFctReset(audio returns 0x%x", err); return err; } } /** * Update state automaton */ pC->m_State = M4PTO3GPP_kState_OPENED; /** * Get the max File size */ switch(pC->m_Params.OutputFileMaxSize) { case M4PTO3GPP_k50_KB: pC->m_MaxFileSize = 50000; break; case M4PTO3GPP_k75_KB: pC->m_MaxFileSize = 75000; break; case M4PTO3GPP_k100_KB: pC->m_MaxFileSize = 100000; break; case M4PTO3GPP_k150_KB: pC->m_MaxFileSize = 150000; break; case M4PTO3GPP_k200_KB: pC->m_MaxFileSize = 200000; break; case M4PTO3GPP_k300_KB: pC->m_MaxFileSize = 300000; break; case M4PTO3GPP_k400_KB: pC->m_MaxFileSize = 400000; break; case M4PTO3GPP_k500_KB: pC->m_MaxFileSize = 500000; break; case M4PTO3GPP_kUNLIMITED: default: break; } M4OSA_TRACE3_0("M4PTO3GPP_Open(): returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4PTO3GPP_Step(M4PTO3GPP_Context pContext); * @brief Perform one step of trancoding. * @note * @param pContext (IN) M4PTO3GPP context * @return M4NO_ERROR No error * @return M4ERR_PARAMETER pContext is M4OSA_NULL * @return M4ERR_STATE: M4PTO3GPP is not in an appropriate state for this function * to be called * @return M4PTO3GPP_WAR_END_OF_PROCESSING Encoding completed ****************************************************************************** */ /*********************************************************/ M4OSA_ERR M4PTO3GPP_Step(M4PTO3GPP_Context pContext) /*********************************************************/ { M4PTO3GPP_InternalContext *pC = (M4PTO3GPP_InternalContext*)(pContext); M4OSA_ERR err = M4NO_ERROR; M4OSA_UInt32 l_uiAudioStepCount = 0; M4OSA_Int32 JumpToTime = 0; M4OSA_Time mtIncCts; /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL==pContext), M4ERR_PARAMETER, "M4PTO3GPP_Step: pContext is M4OSA_NULL"); /** * Check state automaton */ if ( !((M4PTO3GPP_kState_OPENED == pC->m_State) || (M4PTO3GPP_kState_READY == pC->m_State)) ) { M4OSA_TRACE1_1("M4PTO3GPP_Step(): Wrong State (%d), returning M4ERR_STATE", pC->m_State); return M4ERR_STATE; } /******************************************************************/ /** * In case this is the first step, we prepare the decoder, the encoder and the writer */ if (M4PTO3GPP_kState_OPENED == pC->m_State) { M4OSA_TRACE2_0("M4PTO3GPP_Step(): This is the first step, \ calling M4PTO3GPP_Ready4Processing"); /** * Prepare the reader, the decoder, the encoder, the writer... */ err = M4PTO3GPP_Ready4Processing(pC); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Step(): M4PTO3GPP_Ready4Processing() returns 0x%x", err); return err; } /** * Update state automaton */ pC->m_State = M4PTO3GPP_kState_READY; M4OSA_TRACE3_0("M4PTO3GPP_Step(): returning M4NO_ERROR (a)"); return M4NO_ERROR; /**< we only do that in the first step, \ first REAL step will be the next one */ } /* * Check if we reached the targeted file size. * We do that before the encoding, because the core encoder has to know if this is * the last frame to encode */ err = pC->m_pWriterGlobInt->pFctGetOption(pC->m_p3gpWriterContext, M4WRITER_kFileSizeAudioEstimated, (M4OSA_DataOption) &pC->m_CurrentFileSize); if ((0 != pC->m_MaxFileSize) && /**< Add a marge to the file size in order to never exceed the max file size */ ((pC->m_CurrentFileSize + M4PTO3GPP_MARGE_OF_FILE_SIZE) >= pC->m_MaxFileSize)) { pC->m_IsLastPicture = M4OSA_TRUE; } /****************************************************************** * At that point we are in M4PTO3GPP_kState_READY state * We perform one step of video encoding ******************************************************************/ /************* VIDEO ENCODING ***************/ if (M4PTO3GPP_kStreamState_STARTED == pC->m_VideoState) /**<If the video encoding is going on*/ { /** * Call the encoder */ pC->m_NbCurrentFrame++; /* Check if it is the last frame the to encode */ if((pC->m_Params.NbVideoFrames > 0) \ && (pC->m_NbCurrentFrame >= pC->m_Params.NbVideoFrames)) { pC->m_IsLastPicture = M4OSA_TRUE; } M4OSA_TRACE2_2("M4PTO3GPP_Step(): Calling pEncoderInt->pFctEncode with videoCts = %.2f\ nb = %lu", pC->m_mtCts, pC->m_NbCurrentFrame); err = pC->m_pEncoderInt->pFctEncode(pC->m_pMp4EncoderContext, M4OSA_NULL, /**< The input plane is null because the input Picture will be obtained by the\ VPP filter from the context */ pC->m_mtCts, (pC->m_IsLastPicture ? M4ENCODER_kLastFrame : M4ENCODER_kNormalFrame) ); /**< Last param set to M4OSA_TRUE signals that this is the last frame to be encoded,\ M4OSA_FALSE else */ M4OSA_TRACE3_2("M4PTO3GPP_Step(): pEncoderInt->pFctEncode returns 0x%x, vidFormat =0x%x", err, pC->m_Params.OutputVideoFormat); if((M4NO_ERROR == err) && (M4VIDEOEDITING_kH264 == pC->m_Params.OutputVideoFormat)) { /* Check if last frame.* * */ if(M4OSA_TRUE == pC->m_IsLastPicture) { M4OSA_TRACE3_0("M4PTO3GPP_Step(): Last picture"); pC->m_VideoState = M4PTO3GPP_kStreamState_FINISHED; } } if (M4WAR_NO_MORE_AU == err) /**< The video encoding is finished */ { M4OSA_TRACE3_0("M4PTO3GPP_Step(): pEncoderInt->pFctEncode returns M4WAR_NO_MORE_AU"); pC->m_VideoState = M4PTO3GPP_kStreamState_FINISHED; } else if (M4NO_ERROR != err) /**< Unexpected error code */ { if( (((M4OSA_UInt32)M4WAR_WRITER_STOP_REQ) == err) || (((M4OSA_UInt32)M4ERR_ALLOC) == err) ) { M4OSA_TRACE1_0("M4PTO3GPP_Step: returning ERR_PTO3GPP_ENCODER_ACCES_UNIT_ERROR"); return ERR_PTO3GPP_ENCODER_ACCES_UNIT_ERROR; } else { M4OSA_TRACE1_1("M4PTO3GPP_Step(): pEncoderInt->pFctEncode(last) (a) returns 0x%x", err); return err; } } } /**< End of video encoding */ /****** AUDIO TRANSCODING (read + null encoding + write) ******/ if (M4PTO3GPP_kStreamState_STARTED == pC->m_AudioState) { while ( (M4PTO3GPP_kStreamState_STARTED == pC->m_AudioState) && (pC->m_mtAudioCts < pC->m_mtNextCts)) { l_uiAudioStepCount++; if (M4OSA_FALSE == pC->m_bAudioPaddingSilence) { /**< Read the next audio AU in the input Audio file */ err = pC->m_pReaderDataInt->m_pFctGetNextAu(pC->m_pAudioReaderContext, (M4_StreamHandler*)pC->m_pReaderAudioStream, pC->m_pReaderAudioAU); pC->m_mtAudioCts = pC->m_pReaderAudioAU->m_CTS + pC->m_AudioOffSet; if (M4WAR_NO_MORE_AU == err) /* The audio transcoding is finished */ { M4OSA_TRACE2_0("M4PTO3GPP_Step():\ pReaderDataInt->m_pFctGetNextAu(audio) returns \ M4WAR_NO_MORE_AU"); switch(pC->m_Params.AudioPaddingMode) { case M4PTO3GPP_kAudioPaddingMode_None: pC->m_AudioState = M4PTO3GPP_kStreamState_FINISHED; break; case M4PTO3GPP_kAudioPaddingMode_Silence: if (M4DA_StreamTypeAudioAmrNarrowBand != pC->m_pReaderAudioStream->m_basicProperties.m_streamType) /**< Do nothing if the input audio file format is not AMR */ { pC->m_AudioState = M4PTO3GPP_kStreamState_FINISHED; } else { pC->m_bAudioPaddingSilence = M4OSA_TRUE; } break; case M4PTO3GPP_kAudioPaddingMode_Loop: /**< Jump to the beginning of the audio file */ err = pC->m_pReaderGlobInt->m_pFctJump(pC->m_pAudioReaderContext, (M4_StreamHandler*)pC->m_pReaderAudioStream, &JumpToTime); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Step(): \ pReaderDataInt->m_pFctReset(audio returns 0x%x", err); return err; } if (M4DA_StreamTypeAudioAmrNarrowBand == pC->m_pReaderAudioStream->m_basicProperties.m_streamType) { pC->m_mtAudioCts += 20; /*< SEMC bug fixed at Lund */ pC->m_AudioOffSet = pC->m_mtAudioCts; /** * 'BZZZ' bug fix: * add a silence frame */ mtIncCts = (M4OSA_Time)((pC->m_mtAudioCts) * (pC->m_pWriterAudioStream->timeScale / 1000.0)); err = M4PTO3GPP_writeAmrSilence122Frame(pC->m_pWriterDataInt, pC->m_p3gpWriterContext, &pC->m_WriterAudioAU, mtIncCts); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Step(): \ M4PTO3GPP_AddAmrSilenceSid returns 0x%x", err); return err; }/**< Add => no audio cts increment...*/ } else { pC->m_AudioOffSet = pC->m_mtAudioCts + pC->m_DeltaAudioCts; } break; } /* end of: switch */ } else if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Step(): pReaderDataInt->m_pFctGetNextAu(Audio)\ returns 0x%x", err); return err; } else { /** * Save the delta Cts (AAC only) */ pC->m_DeltaAudioCts = pC->m_pReaderAudioAU->m_CTS - pC->m_PrevAudioCts; pC->m_PrevAudioCts = pC->m_pReaderAudioAU->m_CTS; /** * Prepare the writer AU */ err = pC->m_pWriterDataInt->pStartAU(pC->m_p3gpWriterContext, 1, &pC->m_WriterAudioAU); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Step(): pWriterDataInt->pStartAU(Audio)\ returns 0x%x", err); return err; } /** * Copy audio data from reader AU to writer AU */ M4OSA_TRACE2_1("M4PTO3GPP_Step(): Copying audio AU: size=%d", pC->m_pReaderAudioAU->m_size); memcpy((void *)pC->m_WriterAudioAU.dataAddress, (void *)pC->m_pReaderAudioAU->m_dataAddress, pC->m_pReaderAudioAU->m_size); pC->m_WriterAudioAU.size = pC->m_pReaderAudioAU->m_size; /** * Convert CTS unit from milliseconds to timescale */ if (M4DA_StreamTypeAudioAmrNarrowBand != pC->m_pReaderAudioStream->m_basicProperties.m_streamType) { pC->m_WriterAudioAU.CTS = (M4OSA_Time) ((pC->m_AudioOffSet + pC->m_pReaderAudioAU->m_CTS) * pC->m_pWriterAudioStream->timeScale / 1000.0); } else { pC->m_WriterAudioAU.CTS = (M4OSA_Time)(pC->m_mtAudioCts * (pC->m_pWriterAudioStream->timeScale / 1000.0)); } pC->m_WriterAudioAU.nbFrag = 0; M4OSA_TRACE2_1("M4PTO3GPP_Step(): audio AU: CTS=%d ms", pC->m_mtAudioCts /*pC->m_pReaderAudioAU->m_CTS*/); /** * Write it to the output file */ err = pC->m_pWriterDataInt->pProcessAU(pC->m_p3gpWriterContext, 1, &pC->m_WriterAudioAU); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Step(): pWriterDataInt->pProcessAU(Audio)\ returns 0x%x", err); return err; } } } else /**< M4OSA_TRUE == pC->m_bAudioPaddingSilence */ { if (M4DA_StreamTypeAudioAmrNarrowBand == pC->m_pReaderAudioStream->m_basicProperties.m_streamType) { /** * Fill in audio au with silence */ pC->m_mtAudioCts += 20; /** * Padd with silence */ mtIncCts = (M4OSA_Time)(pC->m_mtAudioCts * (pC->m_pWriterAudioStream->timeScale / 1000.0)); err = M4PTO3GPP_writeAmrSilence048Frame(pC->m_pWriterDataInt, pC->m_p3gpWriterContext, &pC->m_WriterAudioAU, mtIncCts); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Step(): M4PTO3GPP_AddAmrSilenceSid returns 0x%x", err); return err; } } else /**< Do nothing if the input audio file format is not AMR */ { pC->m_AudioState = M4PTO3GPP_kStreamState_FINISHED; } } } /**< while */ } /**< End of audio encoding */ pC->m_mtCts = pC->m_mtNextCts; /** * The transcoding is finished when no stream is being encoded anymore */ if (M4PTO3GPP_kStreamState_FINISHED == pC->m_VideoState) { pC->m_State = M4PTO3GPP_kState_FINISHED; M4OSA_TRACE2_0("M4PTO3GPP_Step(): transcoding finished, returning M4WAR_NO_MORE_AU"); return M4PTO3GPP_WAR_END_OF_PROCESSING; } M4OSA_TRACE3_0("M4PTO3GPP_Step(): returning M4NO_ERROR (b)"); return M4NO_ERROR; } /** ****************************************************************************** * M4OSA_ERR M4PTO3GPP_Close(M4PTO3GPP_Context pContext); * @brief Finish the M4PTO3GPP transcoding. * @note The output 3GPP file is ready to be played after this call * @param pContext (IN) M4PTO3GPP context * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (If Debug Level >= 2) * @return M4ERR_STATE: M4PTO3GPP is not in an appropriate state for this function to be called ****************************************************************************** */ /*********************************************************/ M4OSA_ERR M4PTO3GPP_Close(M4PTO3GPP_Context pContext) /*********************************************************/ { M4PTO3GPP_InternalContext *pC = (M4PTO3GPP_InternalContext*)(pContext); M4OSA_ERR osaErr = M4NO_ERROR; M4OSA_UInt32 lastCTS; M4ENCODER_Header* encHeader; M4SYS_StreamIDmemAddr streamHeader; M4OSA_TRACE3_1("M4PTO3GPP_Close called with pContext=0x%x", pContext); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL==pContext), M4ERR_PARAMETER, "M4PTO3GPP_Close:\ pContext is M4OSA_NULL"); /* Check state automaton */ if ((pC->m_State != M4PTO3GPP_kState_OPENED) && (pC->m_State != M4PTO3GPP_kState_READY) && (pC->m_State != M4PTO3GPP_kState_FINISHED)) { M4OSA_TRACE1_1("M4PTO3GPP_Close(): Wrong State (%d), returning M4ERR_STATE", pC->m_State); return M4ERR_STATE; } /*************************************/ /******** Finish the encoding ********/ /*************************************/ if (M4PTO3GPP_kState_READY == pC->m_State) { pC->m_State = M4PTO3GPP_kState_FINISHED; } if (M4PTO3GPP_kEncoderRunning == pC->m_eEncoderState) { if (pC->m_pEncoderInt->pFctStop != M4OSA_NULL) { osaErr = pC->m_pEncoderInt->pFctStop(pC->m_pMp4EncoderContext); if (M4NO_ERROR != osaErr) { M4OSA_TRACE1_1("M4PTO3GPP_close: m_pEncoderInt->pFctStop returns 0x%x", osaErr); /* Well... how the heck do you handle a failed cleanup? */ } } pC->m_eEncoderState = M4PTO3GPP_kEncoderStopped; } /* Has the encoder actually been opened? Don't close it if that's not the case. */ if (M4PTO3GPP_kEncoderStopped == pC->m_eEncoderState) { osaErr = pC->m_pEncoderInt->pFctClose(pC->m_pMp4EncoderContext); if (M4NO_ERROR != osaErr) { M4OSA_TRACE1_1("M4PTO3GPP_close: m_pEncoderInt->pFctClose returns 0x%x", osaErr); /* Well... how the heck do you handle a failed cleanup? */ } pC->m_eEncoderState = M4PTO3GPP_kEncoderClosed; } /*******************************/ /******** Close 3GP out ********/ /*******************************/ if (M4OSA_NULL != pC->m_p3gpWriterContext) /* happens in state _SET */ { /* HW encoder: fetch the DSI from the shell video encoder, and feed it to the writer before closing it. */ if ((M4VIDEOEDITING_kMPEG4 == pC->m_Params.OutputVideoFormat) || (M4VIDEOEDITING_kH264 == pC->m_Params.OutputVideoFormat)) { osaErr = pC->m_pEncoderInt->pFctGetOption(pC->m_pMp4EncoderContext, M4ENCODER_kOptionID_EncoderHeader, (M4OSA_DataOption)&encHeader); if ( (M4NO_ERROR != osaErr) || (M4OSA_NULL == encHeader->pBuf) ) { M4OSA_TRACE1_1("M4PTO3GPP_close: failed to get the encoder header (err 0x%x)", osaErr); /**< no return here, we still have stuff to deallocate after close, even if \ it fails. */ } else { /* set this header in the writer */ streamHeader.streamID = M4PTO3GPP_WRITER_VIDEO_STREAM_ID; streamHeader.size = encHeader->Size; streamHeader.addr = (M4OSA_MemAddr32)encHeader->pBuf; osaErr = pC->m_pWriterGlobInt->pFctSetOption(pC->m_p3gpWriterContext, M4WRITER_kDSI, &streamHeader); if (M4NO_ERROR != osaErr) { M4OSA_TRACE1_1("M4PTO3GPP_close: failed to set the DSI in the writer \ (err 0x%x) ", osaErr); } } } /* Update last Video CTS */ lastCTS = (M4OSA_UInt32)pC->m_mtCts; osaErr = pC->m_pWriterGlobInt->pFctSetOption(pC->m_p3gpWriterContext, (M4OSA_UInt32)M4WRITER_kMaxFileDuration, &lastCTS); if (M4NO_ERROR != osaErr) { M4OSA_TRACE1_1("M4PTO3GPP_Close: SetOption(M4WRITER_kMaxFileDuration) returns 0x%x", osaErr); } /* Write and close the 3GP output file */ osaErr = pC->m_pWriterGlobInt->pFctCloseWrite(pC->m_p3gpWriterContext); if (M4NO_ERROR != osaErr) { M4OSA_TRACE1_1("M4PTO3GPP_Close: pWriterGlobInt->pFctCloseWrite returns 0x%x", osaErr); /**< don't return yet, we have to close other things */ } pC->m_p3gpWriterContext = M4OSA_NULL; } /** * State transition */ pC->m_State = M4PTO3GPP_kState_CLOSED; M4OSA_TRACE3_1("M4PTO3GPP_Close(): returning 0x%x", osaErr); return osaErr; } /** ****************************************************************************** * M4OSA_ERR M4PTO3GPP_CleanUp(M4PTO3GPP_Context pContext); * @brief Free all resources used by the M4PTO3GPP. * @note The context is no more valid after this call * @param pContext (IN) M4PTO3GPP context * @return M4NO_ERROR: No error * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (If Debug Level >= 2) ****************************************************************************** */ /*********************************************************/ M4OSA_ERR M4PTO3GPP_CleanUp(M4PTO3GPP_Context pContext) /*********************************************************/ { M4OSA_ERR err = M4NO_ERROR; M4PTO3GPP_InternalContext *pC = (M4PTO3GPP_InternalContext*)(pContext); M4OSA_TRACE3_1("M4PTO3GPP_CleanUp called with pContext=0x%x", pContext); /** * Check input parameters */ M4OSA_DEBUG_IF2((M4OSA_NULL==pContext),M4ERR_PARAMETER, "M4PTO3GPP_CleanUp: pContext \ is M4OSA_NULL"); /** * First call Close, if needed, to clean the video encoder */ if ((M4PTO3GPP_kState_OPENED == pC->m_State) || (M4PTO3GPP_kState_READY == pC->m_State) || (M4PTO3GPP_kState_FINISHED == pC->m_State)) { err = M4PTO3GPP_Close(pContext); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_CleanUp: M4PTO3GPP_Close returns 0x%x", err); /**< don't return, we have to free other components */ } } /** * Free Audio reader stuff, if needed */ if (M4OSA_NULL != pC->m_pAudioReaderContext) /**< may be M4OSA_NULL if M4PTO3GPP_Open was not\ called */ { err = pC->m_pReaderGlobInt->m_pFctClose(pC->m_pAudioReaderContext); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_CleanUp: pReaderGlobInt->m_pFctClose returns 0x%x", err); /**< don't return, we have to free other components */ } err = pC->m_pReaderGlobInt->m_pFctDestroy(pC->m_pAudioReaderContext); pC->m_pAudioReaderContext = M4OSA_NULL; if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_CleanUp: pReaderGlobInt->m_pFctDestroy returns 0x%x", err); /**< don't return, we have to free other components */ } } if (M4OSA_NULL != pC->m_pReaderAudioAU) { free(pC->m_pReaderAudioAU); pC->m_pReaderAudioAU = M4OSA_NULL; } /** * Free video encoder stuff, if needed */ if (M4OSA_NULL != pC->m_pMp4EncoderContext) { err = pC->m_pEncoderInt->pFctCleanup(pC->m_pMp4EncoderContext); pC->m_pMp4EncoderContext = M4OSA_NULL; if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_CleanUp: pEncoderInt->pFctDestroy returns 0x%x", err); /**< don't return, we have to free other components */ } } if (M4OSA_NULL != pC->m_pWriterVideoStream) { free(pC->m_pWriterVideoStream); pC->m_pWriterVideoStream = M4OSA_NULL; } if (M4OSA_NULL != pC->m_pWriterAudioStream) { free(pC->m_pWriterAudioStream); pC->m_pWriterAudioStream = M4OSA_NULL; } if (M4OSA_NULL != pC->m_pWriterVideoStreamInfo) { free(pC->m_pWriterVideoStreamInfo); pC->m_pWriterVideoStreamInfo = M4OSA_NULL; } if (M4OSA_NULL != pC->m_pWriterAudioStreamInfo) { free(pC->m_pWriterAudioStreamInfo); pC->m_pWriterAudioStreamInfo = M4OSA_NULL; } /** * Free the shells interfaces */ if (M4OSA_NULL != pC->m_pReaderGlobInt) { free(pC->m_pReaderGlobInt); pC->m_pReaderGlobInt = M4OSA_NULL; } if (M4OSA_NULL != pC->m_pReaderDataInt) { free(pC->m_pReaderDataInt); pC->m_pReaderDataInt = M4OSA_NULL; } if(M4OSA_NULL != pC->m_pEncoderInt) { free(pC->m_pEncoderInt); pC->m_pEncoderInt = M4OSA_NULL; } if(M4OSA_NULL != pC->m_pWriterGlobInt) { free(pC->m_pWriterGlobInt); pC->m_pWriterGlobInt = M4OSA_NULL; } if(M4OSA_NULL != pC->m_pWriterDataInt) { free(pC->m_pWriterDataInt); pC->m_pWriterDataInt = M4OSA_NULL; } /**< Do not free pC->pOsaMemoryPtrFct and pC->pOsaMemoryPtrFct, because it's owned by the \ application */ /** * Free the context itself */ free(pC); pC = M4OSA_NULL; M4OSA_TRACE3_0("M4PTO3GPP_CleanUp(): returning M4NO_ERROR"); return M4NO_ERROR; } /********************* INTERNAL FUNCTIONS *********************/ /** ****************************************************************************** * M4OSA_ERR M4PTO3GPP_Ready4Processing(M4PTO3GPP_InternalContext* pC); * @brief Prepare all resources and interfaces for the transcoding. * @note It is called by the first M4OSA_Step() call * @param pC (IN) M4PTO3GPP private context * @return M4NO_ERROR: No error * @return Any error returned by an underlaying module ****************************************************************************** */ /******************************************************/ M4OSA_ERR M4PTO3GPP_Ready4Processing(M4PTO3GPP_InternalContext* pC) /******************************************************/ { M4OSA_ERR err = M4NO_ERROR; M4WRITER_OutputFileType outputFileType; M4OSA_UInt32 uiVersion; M4ENCODER_Format encFormat; M4ENCODER_AdvancedParams EncParams; /**< Encoder advanced parameters */ M4SYS_StreamIDValue optionValue; M4OSA_TRACE3_1("M4PTO3GPP_Ready4Processing called with pC=0x%x", pC); /******************************/ /******************************/ /********************************************/ /******** ********/ /******** Video Encoder Parames init ********/ /******** ********/ /********************************************/ /** * Get the correct encoder interface */ switch(pC->m_Params.OutputVideoFormat) { case M4VIDEOEDITING_kMPEG4: #ifdef M4VSS_SUPPORT_ENCODER_MPEG4 err = VideoEditorVideoEncoder_getInterface_MPEG4(&encFormat, &pC->m_pEncoderInt, M4ENCODER_OPEN_ADVANCED); #else /* software MPEG4 encoder not available! */ M4OSA_TRACE1_0("No MPEG4 encoder available! Did you forget to register one?"); err = M4ERR_STATE; #endif /* software MPEG4 encoder available? */ break; case M4VIDEOEDITING_kH263: #ifdef M4VSS_SUPPORT_ENCODER_MPEG4 err = VideoEditorVideoEncoder_getInterface_H263(&encFormat, &pC->m_pEncoderInt, M4ENCODER_OPEN_ADVANCED); #else /* software H263 encoder not available! */ M4OSA_TRACE1_0("No H263 encoder available! Did you forget to register one?"); err = M4ERR_STATE; #endif /* software H263 encoder available? */ break; case M4VIDEOEDITING_kH264: #ifdef M4VSS_SUPPORT_ENCODER_AVC err = VideoEditorVideoEncoder_getInterface_H264(&encFormat, &pC->m_pEncoderInt, M4ENCODER_OPEN_ADVANCED); #else /* software H264 encoder not available! */ M4OSA_TRACE1_0("M4PTO3GPP_Ready4Processing: No H264 encoder available!\ Did you forget to register one?"); err = M4ERR_STATE; #endif /* software H264 encoder available? */ break; default: M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: unknown format 0x%x returning \ ERR_M4PTO3GPP_UNDEFINED_OUTPUT_VIDEO_FORMAT", pC->m_Params.OutputVideoFormat); return ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_FORMAT; } if (M4NO_ERROR != err) { M4OSA_TRACE1_1("switch(pC->m_Params.OutputVideoFormat): getInterfaces returns 0x%x", err); return err; } /** * Fill encoder parameters according to M4PTO3GPP settings */ /** * Video frame size */ switch(pC->m_Params.OutputVideoFrameSize) { case M4VIDEOEDITING_kSQCIF : EncParams.FrameHeight = M4ENCODER_SQCIF_Height; EncParams.FrameWidth = M4ENCODER_SQCIF_Width; break; case M4VIDEOEDITING_kQQVGA : EncParams.FrameHeight = M4ENCODER_QQVGA_Height; EncParams.FrameWidth = M4ENCODER_QQVGA_Width; break; case M4VIDEOEDITING_kQCIF : EncParams.FrameHeight = M4ENCODER_QCIF_Height; EncParams.FrameWidth = M4ENCODER_QCIF_Width; break; case M4VIDEOEDITING_kQVGA : EncParams.FrameHeight = M4ENCODER_QVGA_Height; EncParams.FrameWidth = M4ENCODER_QVGA_Width; break; case M4VIDEOEDITING_kCIF : EncParams.FrameHeight = M4ENCODER_CIF_Height; EncParams.FrameWidth = M4ENCODER_CIF_Width; break; case M4VIDEOEDITING_kVGA : EncParams.FrameHeight = M4ENCODER_VGA_Height; EncParams.FrameWidth = M4ENCODER_VGA_Width; break; /* +PR LV5807 */ case M4VIDEOEDITING_kWVGA : EncParams.FrameHeight = M4ENCODER_WVGA_Height; EncParams.FrameWidth = M4ENCODER_WVGA_Width; break; case M4VIDEOEDITING_kNTSC: EncParams.FrameHeight = M4ENCODER_NTSC_Height; EncParams.FrameWidth = M4ENCODER_NTSC_Width; break; /* -PR LV5807 */ /* +CR Google */ case M4VIDEOEDITING_k640_360: EncParams.FrameHeight = M4ENCODER_640_360_Height; EncParams.FrameWidth = M4ENCODER_640_360_Width; break; case M4VIDEOEDITING_k854_480: EncParams.FrameHeight = M4ENCODER_854_480_Height; EncParams.FrameWidth = M4ENCODER_854_480_Width; break; case M4VIDEOEDITING_k1280_720: EncParams.FrameHeight = M4ENCODER_1280_720_Height; EncParams.FrameWidth = M4ENCODER_1280_720_Width; break; case M4VIDEOEDITING_k1080_720: EncParams.FrameHeight = M4ENCODER_1080_720_Height; EncParams.FrameWidth = M4ENCODER_1080_720_Width; break; case M4VIDEOEDITING_k960_720: EncParams.FrameHeight = M4ENCODER_960_720_Height; EncParams.FrameWidth = M4ENCODER_960_720_Width; break; case M4VIDEOEDITING_k1920_1080: EncParams.FrameHeight = M4ENCODER_1920_1080_Height; EncParams.FrameWidth = M4ENCODER_1920_1080_Width; break; /* -CR Google */ default : M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: unknown format 0x%x returning \ ERR_M4PTO3GPP_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE", pC->m_Params.OutputVideoFrameSize); return ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE; } EncParams.InputFormat = M4ENCODER_kIYUV420; /** * Video bitrate */ switch(pC->m_Params.OutputVideoBitrate) { case M4VIDEOEDITING_k16_KBPS: case M4VIDEOEDITING_k24_KBPS: case M4VIDEOEDITING_k32_KBPS: case M4VIDEOEDITING_k48_KBPS: case M4VIDEOEDITING_k64_KBPS: case M4VIDEOEDITING_k96_KBPS: case M4VIDEOEDITING_k128_KBPS: case M4VIDEOEDITING_k192_KBPS: case M4VIDEOEDITING_k256_KBPS: case M4VIDEOEDITING_k288_KBPS: case M4VIDEOEDITING_k384_KBPS: case M4VIDEOEDITING_k512_KBPS: case M4VIDEOEDITING_k800_KBPS: /*+ New Encoder bitrates */ case M4VIDEOEDITING_k2_MBPS: case M4VIDEOEDITING_k5_MBPS: case M4VIDEOEDITING_k8_MBPS: /*- New Encoder bitrates */ EncParams.Bitrate = pC->m_Params.OutputVideoBitrate; break; case M4VIDEOEDITING_kVARIABLE_KBPS: /*+ New Encoder bitrates */ EncParams.Bitrate = M4VIDEOEDITING_k8_MBPS; /*- New Encoder bitrates */ break; default : M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: unknown format 0x%x returning\ ERR_M4PTO3GPP_UNDEFINED_OUTPUT_VIDEO_BITRATE", pC->m_Params.OutputVideoBitrate); return ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_BITRATE; } /** * Video format */ switch(pC->m_Params.OutputVideoFormat) { case M4VIDEOEDITING_kMPEG4 : EncParams.Format = M4ENCODER_kMPEG4; break; case M4VIDEOEDITING_kH263 : EncParams.Format = M4ENCODER_kH263; break; case M4VIDEOEDITING_kH264: EncParams.Format = M4ENCODER_kH264; break; default : M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: unknown format 0x%x returning\ ERR_M4PTO3GPP_UNDEFINED_OUTPUT_VIDEO_FORMAT", pC->m_Params.OutputVideoFormat); return ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_FORMAT; } /** * Video frame rate (set it to max = 30 fps) */ EncParams.uiTimeScale = 30; EncParams.uiRateFactor = 1; EncParams.FrameRate = M4ENCODER_k30_FPS; /******************************/ /******** 3GP out init ********/ /******************************/ /* Get the 3GPP writer interface */ err = M4WRITER_3GP_getInterfaces(&outputFileType, &pC->m_pWriterGlobInt, &pC->m_pWriterDataInt); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4WRITER_3GP_getInterfaces: M4WRITER_3GP_getInterfaces returns 0x%x", err); return err; } /* Init the 3GPP writer */ err = pC->m_pWriterGlobInt->pFctOpen(&pC->m_p3gpWriterContext, pC->m_Params.pOutput3gppFile, pC->pOsalFileWrite, pC->m_Params.pTemporaryFile, pC->pOsalFileRead); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: pWriterGlobInt->pFctOpen returns 0x%x", err); return err; } /** * Link to the writer context in the writer interface */ pC->m_pWriterDataInt->pWriterContext = pC->m_p3gpWriterContext; /** * Set the product description string in the written file */ err = pC->m_pWriterGlobInt->pFctSetOption(pC->m_p3gpWriterContext, M4WRITER_kEmbeddedString, (M4OSA_DataOption)M4PTO3GPP_SIGNATURE); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: \ pWriterGlobInt->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->m_pWriterGlobInt->pFctSetOption(pC->m_p3gpWriterContext, M4WRITER_kEmbeddedVersion, (M4OSA_DataOption)&uiVersion); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: \ pWriterGlobInt->pFctSetOption(M4WRITER_kEmbeddedVersion) returns 0x%x", err); return err; } /** * Allocate and fill the video stream structures for the writer */ pC->m_pWriterVideoStream = (M4SYS_StreamDescription*)M4OSA_32bitAlignedMalloc(sizeof(M4SYS_StreamDescription), M4PTO3GPP, (M4OSA_Char *)"pWriterVideoStream"); if (M4OSA_NULL == pC->m_pWriterVideoStream) { M4OSA_TRACE1_0("M4PTO3GPP_Ready4Processing(): unable to allocate pWriterVideoStream, \ returning M4ERR_ALLOC"); return M4ERR_ALLOC; } pC->m_pWriterVideoStreamInfo = (M4WRITER_StreamVideoInfos*)M4OSA_32bitAlignedMalloc(sizeof(M4WRITER_StreamVideoInfos), M4PTO3GPP, (M4OSA_Char *)"pWriterVideoStreamInfo"); if (M4OSA_NULL == pC->m_pWriterVideoStreamInfo) { M4OSA_TRACE1_0("M4PTO3GPP_Ready4Processing(): unable to allocate pWriterVideoStreamInfo,\ returning M4ERR_ALLOC"); return M4ERR_ALLOC; } /** * Fill Video properties structure for the AddStream method */ pC->m_pWriterVideoStreamInfo->height = EncParams.FrameHeight; pC->m_pWriterVideoStreamInfo->width = EncParams.FrameWidth; pC->m_pWriterVideoStreamInfo->fps = 0; /**< Not used by the core writer */ pC->m_pWriterVideoStreamInfo->Header.pBuf = M4OSA_NULL; /** No header, will be set by setOption */ pC->m_pWriterVideoStreamInfo->Header.Size = 0; /** * Fill Video stream description structure for the AddStream method */ pC->m_pWriterVideoStream->streamID = M4PTO3GPP_WRITER_VIDEO_STREAM_ID; /** * Video format */ switch(pC->m_Params.OutputVideoFormat) { case M4VIDEOEDITING_kMPEG4: pC->m_pWriterVideoStream->streamType = M4SYS_kMPEG_4; break; case M4VIDEOEDITING_kH263: pC->m_pWriterVideoStream->streamType = M4SYS_kH263; break; case M4VIDEOEDITING_kH264: pC->m_pWriterVideoStream->streamType = M4SYS_kH264; break; default : M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: unknown format 0x%x returning \ ERR_M4PTO3GPP_UNDEFINED_OUTPUT_VIDEO_FORMAT", pC->m_Params.OutputVideoFormat); return ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_FORMAT; } /** * Video bitrate */ switch(pC->m_Params.OutputVideoBitrate) { case M4VIDEOEDITING_k16_KBPS: case M4VIDEOEDITING_k24_KBPS: case M4VIDEOEDITING_k32_KBPS: case M4VIDEOEDITING_k48_KBPS: case M4VIDEOEDITING_k64_KBPS: case M4VIDEOEDITING_k96_KBPS: case M4VIDEOEDITING_k128_KBPS: case M4VIDEOEDITING_k192_KBPS: case M4VIDEOEDITING_k256_KBPS: case M4VIDEOEDITING_k288_KBPS: case M4VIDEOEDITING_k384_KBPS: case M4VIDEOEDITING_k512_KBPS: case M4VIDEOEDITING_k800_KBPS: /*+ New Encoder bitrates */ case M4VIDEOEDITING_k2_MBPS: case M4VIDEOEDITING_k5_MBPS: case M4VIDEOEDITING_k8_MBPS: /*- New Encoder bitrates */ pC->m_pWriterVideoStream->averageBitrate = pC->m_Params.OutputVideoBitrate; break; case M4VIDEOEDITING_kVARIABLE_KBPS : pC->m_pWriterVideoStream->averageBitrate = 0; break; default : M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: unknown format 0x%x returning\ ERR_M4PTO3GPP_UNDEFINED_OUTPUT_VIDEO_BITRATE", pC->m_Params.OutputVideoBitrate); return ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_BITRATE; } pC->m_pWriterVideoStream->duration = 0; /**< Duration is not known */ pC->m_pWriterVideoStream->timeScale = 0; /**< Not used by the core writer */ pC->m_pWriterVideoStream->maxBitrate = pC->m_pWriterVideoStream->averageBitrate; pC->m_pWriterVideoStream->profileLevel = 0; /**< Not used by the core writer */ pC->m_pWriterVideoStream->decoderSpecificInfo = (M4OSA_MemAddr32) (pC->m_pWriterVideoStreamInfo); pC->m_pWriterVideoStream->decoderSpecificInfoSize = sizeof(M4WRITER_StreamVideoInfos); /** * Update AU properties for video stream */ pC->m_WriterVideoAU.CTS = pC->m_WriterVideoAU.DTS = 0; /** Reset time */ pC->m_WriterVideoAU.size = 0; pC->m_WriterVideoAU.frag = M4OSA_NULL; pC->m_WriterVideoAU.nbFrag = 0; /** No fragment */ pC->m_WriterVideoAU.stream = pC->m_pWriterVideoStream; pC->m_WriterVideoAU.attribute = AU_RAP; pC->m_WriterVideoAU.dataAddress = M4OSA_NULL; /** * If there is an audio input, allocate and fill the audio stream structures for the writer */ if(M4OSA_NULL != pC->m_pReaderAudioStream) { pC->m_pWriterAudioStream = (M4SYS_StreamDescription*)M4OSA_32bitAlignedMalloc(sizeof(M4SYS_StreamDescription), M4PTO3GPP, (M4OSA_Char *)"pWriterAudioStream"); if (M4OSA_NULL == pC->m_pWriterAudioStream) { M4OSA_TRACE1_0("M4PTO3GPP_Ready4Processing(): unable to allocate pWriterAudioStream, \ returning M4ERR_ALLOC"); return M4ERR_ALLOC; } pC->m_pWriterAudioStreamInfo = (M4WRITER_StreamAudioInfos*)M4OSA_32bitAlignedMalloc(sizeof(M4WRITER_StreamAudioInfos), M4PTO3GPP, (M4OSA_Char *)"pWriterAudioStreamInfo"); if (M4OSA_NULL == pC->m_pWriterAudioStreamInfo) { M4OSA_TRACE1_0("M4PTO3GPP_Ready4Processing(): unable to allocate \ pWriterAudioStreamInfo, returning M4ERR_ALLOC"); return M4ERR_ALLOC; } pC->m_pWriterAudioStreamInfo->nbSamplesPerSec = 0; /**< unused by our shell writer */ pC->m_pWriterAudioStreamInfo->nbBitsPerSample = 0; /**< unused by our shell writer */ pC->m_pWriterAudioStreamInfo->nbChannels = 1; /**< unused by our shell writer */ if( (M4OSA_NULL != pC->m_pReaderAudioStream) && /* audio could have been discarded */ (M4OSA_NULL != pC->m_pReaderAudioStream->m_basicProperties.m_pDecoderSpecificInfo) ) { /* If we copy the stream from the input, we copy its DSI */ pC->m_pWriterAudioStreamInfo->Header.Size = pC->m_pReaderAudioStream->m_basicProperties.m_decoderSpecificInfoSize; pC->m_pWriterAudioStreamInfo->Header.pBuf = (M4OSA_MemAddr8)pC->m_pReaderAudioStream->m_basicProperties.m_pDecoderSpecificInfo; } else { /* Writer will put a default DSI */ pC->m_pWriterAudioStreamInfo->Header.Size = 0; pC->m_pWriterAudioStreamInfo->Header.pBuf = M4OSA_NULL; } /** * Add the audio stream */ switch (pC->m_pReaderAudioStream->m_basicProperties.m_streamType) { case M4DA_StreamTypeAudioAmrNarrowBand: pC->m_pWriterAudioStream->streamType = M4SYS_kAMR; break; case M4DA_StreamTypeAudioAac: pC->m_pWriterAudioStream->streamType = M4SYS_kAAC; break; case M4DA_StreamTypeAudioEvrc: pC->m_pWriterAudioStream->streamType = M4SYS_kEVRC; break; default: M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: unhandled audio format (0x%x),\ returning ERR_PTO3GPP_UNDEFINED_OUTPUT_VIDEO_BITRATE", pC->m_pReaderAudioStream->m_basicProperties.m_streamType); return ERR_PTO3GPP_UNDEFINED_OUTPUT_AUDIO_FORMAT; } /* * Fill Audio stream description structure for the AddStream method */ pC->m_pWriterAudioStream->streamID = M4PTO3GPP_WRITER_AUDIO_STREAM_ID; pC->m_pWriterAudioStream->duration = 0;/**< Duration is not known yet */ pC->m_pWriterAudioStream->timeScale = M4PTO3GPP_WRITER_AUDIO_AMR_TIME_SCALE; pC->m_pWriterAudioStream->profileLevel = M4PTO3GPP_WRITER_AUDIO_PROFILE_LEVEL; pC->m_pWriterAudioStream->averageBitrate = pC->m_pReaderAudioStream->m_basicProperties.m_averageBitRate; pC->m_pWriterAudioStream->maxBitrate = pC->m_pWriterAudioStream->averageBitrate; /** * Our writer shell interface is a little tricky: we put M4WRITER_StreamAudioInfos \ in the DSI pointer... */ pC->m_pWriterAudioStream->decoderSpecificInfo = (M4OSA_MemAddr32)pC->m_pWriterAudioStreamInfo; /** * Update AU properties for audio stream */ pC->m_WriterAudioAU.CTS = pC->m_WriterAudioAU.DTS = 0; /** Reset time */ pC->m_WriterAudioAU.size = 0; pC->m_WriterAudioAU.frag = M4OSA_NULL; pC->m_WriterAudioAU.nbFrag = 0; /** No fragment */ pC->m_WriterAudioAU.stream = pC->m_pWriterAudioStream; pC->m_WriterAudioAU.attribute = AU_RAP; pC->m_WriterAudioAU.dataAddress = M4OSA_NULL; } /************************************/ /******** Video Encoder Init ********/ /************************************/ /** * PTO uses its own bitrate regulation, not the "true" core regulation */ EncParams.bInternalRegulation = M4OSA_TRUE; //M4OSA_FALSE; EncParams.uiStartingQuantizerValue = M4PTO3GPP_QUANTIZER_STEP; EncParams.videoProfile = pC->m_Params.videoProfile; EncParams.videoLevel = pC->m_Params.videoLevel; /** * Other encoder settings */ EncParams.uiHorizontalSearchRange = 0; /* use default */ EncParams.uiVerticalSearchRange = 0; /* use default */ EncParams.bErrorResilience = M4OSA_FALSE; /* no error resilience */ EncParams.uiIVopPeriod = 15; /* use default */ EncParams.uiMotionEstimationTools = 0; /* M4V_MOTION_EST_TOOLS_ALL */ EncParams.bAcPrediction = M4OSA_TRUE; /* use AC prediction */ EncParams.bDataPartitioning = M4OSA_FALSE; /* no data partitioning */ /** * Create video encoder */ err = pC->m_pEncoderInt->pFctInit(&pC->m_pMp4EncoderContext, pC->m_pWriterDataInt, M4PTO3GPP_applyVPP, pC, pC->m_pEncoderExternalAPI, pC->m_pEncoderUserData); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: EncoderInt->pFctInit returns 0x%x", err); return err; } pC->m_eEncoderState = M4PTO3GPP_kEncoderClosed; err = pC->m_pEncoderInt->pFctOpen(pC->m_pMp4EncoderContext, &pC->m_WriterVideoAU, &EncParams); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: EncoderInt->pFctOpen returns 0x%x", err); return err; } pC->m_eEncoderState = M4PTO3GPP_kEncoderStopped; if (M4OSA_NULL != pC->m_pEncoderInt->pFctStart) { err = pC->m_pEncoderInt->pFctStart(pC->m_pMp4EncoderContext); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: EncoderInt->pFctStart returns 0x%x", err); return err; } } pC->m_eEncoderState = M4PTO3GPP_kEncoderRunning; /** * No more setoption on "M4ENCODER_kVideoFragmentSize" here. * It is now automaticly and "smartly" set in the encoder shell. */ /**************************************/ /******** 3GP out add streams ********/ /**************************************/ err = pC->m_pWriterGlobInt->pFctAddStream(pC->m_p3gpWriterContext, pC->m_pWriterVideoStream); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: pWriterGlobInt->pFctAddStream(video) returns\ 0x%x", err); return err; } /** * Set video max au size */ optionValue.streamID = M4PTO3GPP_WRITER_VIDEO_STREAM_ID; optionValue.value = (M4OSA_UInt32)(1.5F * (M4OSA_Float)(pC->m_pWriterVideoStreamInfo->width * pC->m_pWriterVideoStreamInfo->height) * M4PTO3GPP_VIDEO_MIN_COMPRESSION_RATIO); M4OSA_TRACE3_1("M4PTO3GPP_Ready4Processing,M4WRITER_kMaxAUSize: %u",optionValue.value); err = pC->m_pWriterGlobInt->pFctSetOption(pC->m_p3gpWriterContext, (M4OSA_UInt32)M4WRITER_kMaxAUSize,(M4OSA_DataOption) &optionValue); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: pWriterGlobInt->pFctSetOption(video,\ M4WRITER_kMaxAUSize) returns 0x%x", err); return err; } /** * Set video max chunck size */ optionValue.value = (M4OSA_UInt32)((M4OSA_Float)optionValue.value * M4PTO3GPP_VIDEO_AU_SIZE_TO_CHUNCK_SIZE_RATIO); M4OSA_TRACE3_1("M4PTO3GPP_Ready4Processing,M4WRITER_kMaxChunckSize: %u",optionValue.value); err = pC->m_pWriterGlobInt->pFctSetOption(pC->m_p3gpWriterContext, (M4OSA_UInt32)M4WRITER_kMaxChunckSize,(M4OSA_DataOption) &optionValue); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: pWriterGlobInt->pFctSetOption(video,\ M4WRITER_kMaxChunckSize) returns 0x%x", err); return err; } if (M4OSA_NULL != pC->m_pReaderAudioStream) { err = pC->m_pWriterGlobInt->pFctAddStream(pC->m_p3gpWriterContext, pC->m_pWriterAudioStream); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: pWriterGlobInt->pFctAddStream(audio) \ returns 0x%x", err); return err; } /** * Set audio max au size */ optionValue.value = M4PTO3GPP_AUDIO_MAX_AU_SIZE; optionValue.streamID = M4PTO3GPP_WRITER_AUDIO_STREAM_ID; err = pC->m_pWriterGlobInt->pFctSetOption(pC->m_p3gpWriterContext, (M4OSA_UInt32)M4WRITER_kMaxAUSize,(M4OSA_DataOption) &optionValue); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: pWriterGlobInt->pFctSetOption(audio,\ M4WRITER_kMaxAUSize) returns 0x%x", err); return err; } /** * Set audio max chunck size */ optionValue.value = M4PTO3GPP_AUDIO_MAX_CHUNK_SIZE; /**< Magical */ err = pC->m_pWriterGlobInt->pFctSetOption(pC->m_p3gpWriterContext, (M4OSA_UInt32)M4WRITER_kMaxChunckSize,(M4OSA_DataOption) &optionValue); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: pWriterGlobInt->pFctSetOption(audio,\ M4WRITER_kMaxChunckSize) returns 0x%x", err); return err; } } /* * Close the stream registering in order to be ready to write data */ err = pC->m_pWriterGlobInt->pFctStartWriting(pC->m_p3gpWriterContext); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_Ready4Processing: pWriterGlobInt->pFctStartWriting returns 0x%x", err); return err; } M4OSA_TRACE3_0("M4PTO3GPP_Ready4Processing: returning M4NO_ERROR"); return M4NO_ERROR; } /** ****************************************************************************** M4OSA_ERR M4PTO3GPP_writeAmrSilence122Frame(M4WRITER_DataInterface* pWriterDataIntInterface, M4WRITER_Context* pWriterContext, M4SYS_AccessUnit* pWriterAudioAU, M4OSA_Time mtIncCts) * @brief Write an AMR 12.2kbps silence FRAME into the writer * @note Mainly used to fix the 'bzz' bug... * @param pWriterDataIntInterface (IN) writer data interfaces * pWriterContext (IN/OUT)writer context * pWriterAudioAU (OUT) writer audio access unit * mtIncCts (IN) writer CTS * @return M4NO_ERROR: No error ****************************************************************************** */ static M4OSA_ERR M4PTO3GPP_writeAmrSilence122Frame(M4WRITER_DataInterface* pWriterDataIntInterface, M4WRITER_Context* pWriterContext, M4SYS_AccessUnit* pWriterAudioAU, M4OSA_Time mtIncCts) { M4OSA_ERR err; err = pWriterDataIntInterface->pStartAU(pWriterContext, M4PTO3GPP_WRITER_AUDIO_STREAM_ID, pWriterAudioAU); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_writeAmrSilence122Frame: pWriterDataInt->pStartAU(audio) returns \ 0x%x!", err); return err; } memcpy((void *)pWriterAudioAU->dataAddress, (void *)M4PTO3GPP_AMR_AU_SILENCE_122_FRAME, M4PTO3GPP_AMR_AU_SILENCE_FRAME_122_SIZE); pWriterAudioAU->size = M4PTO3GPP_AMR_AU_SILENCE_FRAME_122_SIZE; pWriterAudioAU->CTS = mtIncCts; pWriterAudioAU->nbFrag = 0; err = pWriterDataIntInterface->pProcessAU(pWriterContext, M4PTO3GPP_WRITER_AUDIO_STREAM_ID, pWriterAudioAU); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_writeAmrSilence122Frame: pWriterDataInt->pProcessAU(silence) \ returns 0x%x!", err); return err; } return M4NO_ERROR; } /** ****************************************************************************** M4OSA_ERR M4PTO3GPP_writeAmrSilence048Frame(M4WRITER_DataInterface* pWriterDataIntInterface, M4WRITER_Context* pWriterContext, M4SYS_AccessUnit* pWriterAudioAU, M4OSA_Time mtIncCts) * @brief Write an AMR 12.2kbps silence FRAME into the writer * @note Mainly used to fix the 'bzz' bug... * @param pWriterDataIntInterface (IN) writer data interfaces * pWriterContext (IN/OUT)writer context * pWriterAudioAU (OUT) writer audio access unit * mtIncCts (IN) writer CTS * @return M4NO_ERROR: No error ****************************************************************************** */ static M4OSA_ERR M4PTO3GPP_writeAmrSilence048Frame(M4WRITER_DataInterface* pWriterDataIntInterface, M4WRITER_Context* pWriterContext, M4SYS_AccessUnit* pWriterAudioAU, M4OSA_Time mtIncCts) { M4OSA_ERR err; err = pWriterDataIntInterface->pStartAU(pWriterContext, M4PTO3GPP_WRITER_AUDIO_STREAM_ID, pWriterAudioAU); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_writeAmrSilence048Frame: pWriterDataInt->pStartAU(audio)\ returns 0x%x!", err); return err; } memcpy((void *)pWriterAudioAU->dataAddress, (void *)M4PTO3GPP_AMR_AU_SILENCE_048_FRAME, M4PTO3GPP_AMR_AU_SILENCE_FRAME_048_SIZE); pWriterAudioAU->size = M4PTO3GPP_AMR_AU_SILENCE_FRAME_048_SIZE; pWriterAudioAU->CTS = mtIncCts; pWriterAudioAU->nbFrag = 0; err = pWriterDataIntInterface->pProcessAU(pWriterContext, M4PTO3GPP_WRITER_AUDIO_STREAM_ID, pWriterAudioAU); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4PTO3GPP_writeAmrSilence048Frame: \ pWriterDataInt->pProcessAU(silence) returns 0x%x!", err); return err; } return M4NO_ERROR; }