blob: 64a6f40301cacccde40c5fcf9a04aff7da5f715e [file] [log] [blame]
/*
* 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 M4xVSS_internal.c
* @brief Internal functions of extended Video Studio Service (Video Studio 2.1)
* @note
******************************************************************************
*/
#include "M4OSA_Debug.h"
#include "M4OSA_CharStar.h"
#include "NXPSW_CompilerSwitches.h"
#include "M4VSS3GPP_API.h"
#include "M4VSS3GPP_ErrorCodes.h"
#include "M4xVSS_API.h"
#include "M4xVSS_Internal.h"
/*for rgb16 color effect*/
#include "M4VIFI_Defines.h"
#include "M4VIFI_Clip.h"
/**
* component includes */
#include "M4VFL_transition.h" /**< video effects */
/* Internal header file of VSS is included because of MMS use case */
#include "M4VSS3GPP_InternalTypes.h"
/*Exif header files to add image rendering support (cropping, black borders)*/
#include "M4EXIFC_CommonAPI.h"
// StageFright encoders require %16 resolution
#include "M4ENCODER_common.h"
#define TRANSPARENT_COLOR 0x7E0
/* Prototype of M4VIFI_xVSS_RGB565toYUV420 function (avoid green effect of transparency color) */
M4VIFI_UInt8 M4VIFI_xVSS_RGB565toYUV420(void *pUserData, M4VIFI_ImagePlane *pPlaneIn,
M4VIFI_ImagePlane *pPlaneOut);
/*special MCS function used only in VideoArtist and VideoStudio to open the media in the normal
mode. That way the media duration is accurate*/
extern M4OSA_ERR M4MCS_open_normalMode(M4MCS_Context pContext, M4OSA_Void* pFileIn,
M4VIDEOEDITING_FileType InputFileType,
M4OSA_Void* pFileOut, M4OSA_Void* pTempFile);
/**
******************************************************************************
* prototype M4OSA_ERR M4xVSS_internalStartTranscoding(M4OSA_Context pContext)
* @brief This function initializes MCS (3GP transcoder) with the given
* parameters
* @note The transcoding parameters are given by the internal xVSS context.
* This context contains a pointer on the current element of the
* chained list of MCS parameters.
*
* @param pContext (IN) Pointer on the xVSS edit context
* @return M4NO_ERROR: No error
* @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL
* @return M4ERR_ALLOC: Memory allocation has failed
******************************************************************************
*/
M4OSA_ERR M4xVSS_internalStartTranscoding(M4OSA_Context pContext,
M4OSA_UInt32 *rotationDegree)
{
M4xVSS_Context* xVSS_context = (M4xVSS_Context*)pContext;
M4OSA_ERR err;
M4MCS_Context mcs_context;
M4MCS_OutputParams Params;
M4MCS_EncodingParams Rates;
M4OSA_UInt32 i;
M4VIDEOEDITING_ClipProperties clipProps;
err = M4MCS_init(&mcs_context, xVSS_context->pFileReadPtr, xVSS_context->pFileWritePtr);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("Error in M4MCS_init: 0x%x", err);
return err;
}
err = M4MCS_open(mcs_context, xVSS_context->pMCScurrentParams->pFileIn,
xVSS_context->pMCScurrentParams->InputFileType,
xVSS_context->pMCScurrentParams->pFileOut,
xVSS_context->pMCScurrentParams->pFileTemp);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("Error in M4MCS_open: 0x%x", err);
M4MCS_abort(mcs_context);
return err;
}
/** Get the clip properties
*/
err = M4MCS_getInputFileProperties(mcs_context, &clipProps);
if (err != M4NO_ERROR) {
M4OSA_TRACE1_1("Error in M4MCS_getInputFileProperties: 0x%x", err);
M4MCS_abort(mcs_context);
return err;
}
*rotationDegree = clipProps.videoRotationDegrees;
/**
* Fill MCS parameters with the parameters contained in the current element of the
MCS parameters chained list */
Params.OutputFileType = xVSS_context->pMCScurrentParams->OutputFileType;
Params.OutputVideoFormat = xVSS_context->pMCScurrentParams->OutputVideoFormat;
Params.outputVideoProfile= xVSS_context->pMCScurrentParams->outputVideoProfile;
Params.outputVideoLevel = xVSS_context->pMCScurrentParams->outputVideoLevel;
Params.OutputVideoFrameSize = xVSS_context->pMCScurrentParams->OutputVideoFrameSize;
Params.OutputVideoFrameRate = xVSS_context->pMCScurrentParams->OutputVideoFrameRate;
Params.OutputAudioFormat = xVSS_context->pMCScurrentParams->OutputAudioFormat;
Params.OutputAudioSamplingFrequency =
xVSS_context->pMCScurrentParams->OutputAudioSamplingFrequency;
Params.bAudioMono = xVSS_context->pMCScurrentParams->bAudioMono;
Params.pOutputPCMfile = M4OSA_NULL;
/*FB 2008/10/20: add media rendering parameter to keep aspect ratio*/
switch(xVSS_context->pMCScurrentParams->MediaRendering)
{
case M4xVSS_kResizing:
Params.MediaRendering = M4MCS_kResizing;
break;
case M4xVSS_kCropping:
Params.MediaRendering = M4MCS_kCropping;
break;
case M4xVSS_kBlackBorders:
Params.MediaRendering = M4MCS_kBlackBorders;
break;
default:
break;
}
/**/
// new params after integrating MCS 2.0
// Set the number of audio effects; 0 for now.
Params.nbEffects = 0;
// Set the audio effect; null for now.
Params.pEffects = NULL;
// Set the audio effect; null for now.
Params.bDiscardExif = M4OSA_FALSE;
// Set the audio effect; null for now.
Params.bAdjustOrientation = M4OSA_FALSE;
// new params after integrating MCS 2.0
/**
* Set output parameters */
err = M4MCS_setOutputParams(mcs_context, &Params);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("Error in M4MCS_setOutputParams: 0x%x", err);
M4MCS_abort(mcs_context);
return err;
}
Rates.OutputVideoBitrate = xVSS_context->pMCScurrentParams->OutputVideoBitrate;
Rates.OutputAudioBitrate = xVSS_context->pMCScurrentParams->OutputAudioBitrate;
Rates.BeginCutTime = 0;
Rates.EndCutTime = 0;
Rates.OutputFileSize = 0;
/*FB: transcoding per parts*/
Rates.BeginCutTime = xVSS_context->pMCScurrentParams->BeginCutTime;
Rates.EndCutTime = xVSS_context->pMCScurrentParams->EndCutTime;
Rates.OutputVideoTimescale = xVSS_context->pMCScurrentParams->OutputVideoTimescale;
err = M4MCS_setEncodingParams(mcs_context, &Rates);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("Error in M4MCS_setEncodingParams: 0x%x", err);
M4MCS_abort(mcs_context);
return err;
}
err = M4MCS_checkParamsAndStart(mcs_context);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("Error in M4MCS_checkParamsAndStart: 0x%x", err);
M4MCS_abort(mcs_context);
return err;
}
/**
* Save MCS context to be able to call MCS step function in M4xVSS_step function */
xVSS_context->pMCS_Ctxt = mcs_context;
return M4NO_ERROR;
}
/**
******************************************************************************
* prototype M4OSA_ERR M4xVSS_internalStopTranscoding(M4OSA_Context pContext)
* @brief This function cleans up MCS (3GP transcoder)
* @note
*
* @param pContext (IN) Pointer on the xVSS edit context
* @return M4NO_ERROR: No error
* @return M4ERR_PARAMETER: At least one parameter is M4OSA_NULL
* @return M4ERR_ALLOC: Memory allocation has failed
******************************************************************************
*/
M4OSA_ERR M4xVSS_internalStopTranscoding(M4OSA_Context pContext)
{
M4xVSS_Context* xVSS_context = (M4xVSS_Context*)pContext;
M4OSA_ERR err;
err = M4MCS_close(xVSS_context->pMCS_Ctxt);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalStopTranscoding: Error in M4MCS_close: 0x%x", err);
M4MCS_abort(xVSS_context->pMCS_Ctxt);
return err;
}
/**
* Free this MCS instance */
err = M4MCS_cleanUp(xVSS_context->pMCS_Ctxt);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalStopTranscoding: Error in M4MCS_cleanUp: 0x%x", err);
return err;
}
xVSS_context->pMCS_Ctxt = M4OSA_NULL;
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4xVSS_internalConvertAndResizeARGB8888toYUV420(M4OSA_Void* pFileIn,
* M4OSA_FileReadPointer* pFileReadPtr,
* M4VIFI_ImagePlane* pImagePlanes,
* M4OSA_UInt32 width,
* M4OSA_UInt32 height);
* @brief It Coverts and resizes a ARGB8888 image to YUV420
* @note
* @param pFileIn (IN) The Image input file
* @param pFileReadPtr (IN) Pointer on filesystem functions
* @param pImagePlanes (IN/OUT) Pointer on YUV420 output planes allocated by the user
* ARGB8888 image will be converted and resized to output
* YUV420 plane size
*@param width (IN) width of the ARGB8888
*@param height (IN) height of the ARGB8888
* @return M4NO_ERROR: No error
* @return M4ERR_ALLOC: memory error
* @return M4ERR_PARAMETER: At least one of the function parameters is null
******************************************************************************
*/
M4OSA_ERR M4xVSS_internalConvertAndResizeARGB8888toYUV420(M4OSA_Void* pFileIn,
M4OSA_FileReadPointer* pFileReadPtr,
M4VIFI_ImagePlane* pImagePlanes,
M4OSA_UInt32 width,M4OSA_UInt32 height)
{
M4OSA_Context pARGBIn;
M4VIFI_ImagePlane rgbPlane1 ,rgbPlane2;
M4OSA_UInt32 frameSize_argb=(width * height * 4);
M4OSA_UInt32 frameSize = (width * height * 3); //Size of RGB888 data.
M4OSA_UInt32 i = 0,j= 0;
M4OSA_ERR err=M4NO_ERROR;
M4OSA_UInt8 *pTmpData = (M4OSA_UInt8*) M4OSA_32bitAlignedMalloc(frameSize_argb,
M4VS, (M4OSA_Char*)"Image argb data");
M4OSA_TRACE1_0("M4xVSS_internalConvertAndResizeARGB8888toYUV420 Entering :");
if(pTmpData == M4OSA_NULL) {
M4OSA_TRACE1_0("M4xVSS_internalConvertAndResizeARGB8888toYUV420 :\
Failed to allocate memory for Image clip");
return M4ERR_ALLOC;
}
M4OSA_TRACE1_2("M4xVSS_internalConvertAndResizeARGB8888toYUV420 :width and height %d %d",
width ,height);
/* Get file size (mandatory for chunk decoding) */
err = pFileReadPtr->openRead(&pARGBIn, pFileIn, M4OSA_kFileRead);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_2("M4xVSS_internalConvertAndResizeARGB8888toYUV420 :\
Can't open input ARGB8888 file %s, error: 0x%x\n",pFileIn, err);
free(pTmpData);
pTmpData = M4OSA_NULL;
goto cleanup;
}
err = pFileReadPtr->readData(pARGBIn,(M4OSA_MemAddr8)pTmpData, &frameSize_argb);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_2("M4xVSS_internalConvertAndResizeARGB8888toYUV420 Can't close ARGB8888\
file %s, error: 0x%x\n",pFileIn, err);
pFileReadPtr->closeRead(pARGBIn);
free(pTmpData);
pTmpData = M4OSA_NULL;
goto cleanup;
}
err = pFileReadPtr->closeRead(pARGBIn);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_2("M4xVSS_internalConvertAndResizeARGB8888toYUV420 Can't close ARGB8888 \
file %s, error: 0x%x\n",pFileIn, err);
free(pTmpData);
pTmpData = M4OSA_NULL;
goto cleanup;
}
rgbPlane1.pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(frameSize, M4VS,
(M4OSA_Char*)"Image clip RGB888 data");
if(rgbPlane1.pac_data == M4OSA_NULL)
{
M4OSA_TRACE1_0("M4xVSS_internalConvertAndResizeARGB8888toYUV420 \
Failed to allocate memory for Image clip");
free(pTmpData);
return M4ERR_ALLOC;
}
rgbPlane1.u_height = height;
rgbPlane1.u_width = width;
rgbPlane1.u_stride = width*3;
rgbPlane1.u_topleft = 0;
/** Remove the alpha channel */
for (i=0, j = 0; i < frameSize_argb; i++) {
if ((i % 4) == 0) continue;
rgbPlane1.pac_data[j] = pTmpData[i];
j++;
}
free(pTmpData);
/* To Check if resizing is required with color conversion */
if(width != pImagePlanes->u_width || height != pImagePlanes->u_height)
{
M4OSA_TRACE1_0("M4xVSS_internalConvertAndResizeARGB8888toYUV420 Resizing :");
frameSize = ( pImagePlanes->u_width * pImagePlanes->u_height * 3);
rgbPlane2.pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(frameSize, M4VS,
(M4OSA_Char*)"Image clip RGB888 data");
if(rgbPlane2.pac_data == M4OSA_NULL)
{
M4OSA_TRACE1_0("Failed to allocate memory for Image clip");
free(pTmpData);
return M4ERR_ALLOC;
}
rgbPlane2.u_height = pImagePlanes->u_height;
rgbPlane2.u_width = pImagePlanes->u_width;
rgbPlane2.u_stride = pImagePlanes->u_width*3;
rgbPlane2.u_topleft = 0;
/* Resizing RGB888 to RGB888 */
err = M4VIFI_ResizeBilinearRGB888toRGB888(M4OSA_NULL, &rgbPlane1, &rgbPlane2);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("error when converting from Resize RGB888 to RGB888: 0x%x\n", err);
free(rgbPlane2.pac_data);
free(rgbPlane1.pac_data);
return err;
}
/*Converting Resized RGB888 to YUV420 */
err = M4VIFI_RGB888toYUV420(M4OSA_NULL, &rgbPlane2, pImagePlanes);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("error when converting from RGB888 to YUV: 0x%x\n", err);
free(rgbPlane2.pac_data);
free(rgbPlane1.pac_data);
return err;
}
free(rgbPlane2.pac_data);
free(rgbPlane1.pac_data);
M4OSA_TRACE1_0("RGB to YUV done");
}
else
{
M4OSA_TRACE1_0("M4xVSS_internalConvertAndResizeARGB8888toYUV420 NO Resizing :");
err = M4VIFI_RGB888toYUV420(M4OSA_NULL, &rgbPlane1, pImagePlanes);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("error when converting from RGB to YUV: 0x%x\n", err);
}
free(rgbPlane1.pac_data);
M4OSA_TRACE1_0("RGB to YUV done");
}
cleanup:
M4OSA_TRACE1_0("M4xVSS_internalConvertAndResizeARGB8888toYUV420 leaving :");
return err;
}
/**
******************************************************************************
* M4OSA_ERR M4xVSS_internalConvertARGB8888toYUV420(M4OSA_Void* pFileIn,
* M4OSA_FileReadPointer* pFileReadPtr,
* M4VIFI_ImagePlane* pImagePlanes,
* M4OSA_UInt32 width,
* M4OSA_UInt32 height);
* @brief It Coverts a ARGB8888 image to YUV420
* @note
* @param pFileIn (IN) The Image input file
* @param pFileReadPtr (IN) Pointer on filesystem functions
* @param pImagePlanes (IN/OUT) Pointer on YUV420 output planes allocated by the user
* ARGB8888 image will be converted and resized to output
* YUV420 plane size
* @param width (IN) width of the ARGB8888
* @param height (IN) height of the ARGB8888
* @return M4NO_ERROR: No error
* @return M4ERR_ALLOC: memory error
* @return M4ERR_PARAMETER: At least one of the function parameters is null
******************************************************************************
*/
M4OSA_ERR M4xVSS_internalConvertARGB8888toYUV420(M4OSA_Void* pFileIn,
M4OSA_FileReadPointer* pFileReadPtr,
M4VIFI_ImagePlane** pImagePlanes,
M4OSA_UInt32 width,M4OSA_UInt32 height)
{
M4OSA_ERR err = M4NO_ERROR;
M4VIFI_ImagePlane *yuvPlane = M4OSA_NULL;
yuvPlane = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(3*sizeof(M4VIFI_ImagePlane),
M4VS, (M4OSA_Char*)"M4xVSS_internalConvertRGBtoYUV: Output plane YUV");
if(yuvPlane == M4OSA_NULL) {
M4OSA_TRACE1_0("M4xVSS_internalConvertAndResizeARGB8888toYUV420 :\
Failed to allocate memory for Image clip");
return M4ERR_ALLOC;
}
yuvPlane[0].u_height = height;
yuvPlane[0].u_width = width;
yuvPlane[0].u_stride = width;
yuvPlane[0].u_topleft = 0;
yuvPlane[0].pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(yuvPlane[0].u_height \
* yuvPlane[0].u_width * 1.5, M4VS, (M4OSA_Char*)"imageClip YUV data");
yuvPlane[1].u_height = yuvPlane[0].u_height >>1;
yuvPlane[1].u_width = yuvPlane[0].u_width >> 1;
yuvPlane[1].u_stride = yuvPlane[1].u_width;
yuvPlane[1].u_topleft = 0;
yuvPlane[1].pac_data = (M4VIFI_UInt8*)(yuvPlane[0].pac_data + yuvPlane[0].u_height \
* yuvPlane[0].u_width);
yuvPlane[2].u_height = yuvPlane[0].u_height >>1;
yuvPlane[2].u_width = yuvPlane[0].u_width >> 1;
yuvPlane[2].u_stride = yuvPlane[2].u_width;
yuvPlane[2].u_topleft = 0;
yuvPlane[2].pac_data = (M4VIFI_UInt8*)(yuvPlane[1].pac_data + yuvPlane[1].u_height \
* yuvPlane[1].u_width);
err = M4xVSS_internalConvertAndResizeARGB8888toYUV420( pFileIn,pFileReadPtr,
yuvPlane, width, height);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalConvertAndResizeARGB8888toYUV420 return error: 0x%x\n", err);
free(yuvPlane);
return err;
}
*pImagePlanes = yuvPlane;
M4OSA_TRACE1_0("M4xVSS_internalConvertARGB8888toYUV420 :Leaving");
return err;
}
/**
******************************************************************************
* M4OSA_ERR M4xVSS_PictureCallbackFct (M4OSA_Void* pPictureCtxt,
* M4VIFI_ImagePlane* pImagePlanes,
* M4OSA_UInt32* pPictureDuration);
* @brief It feeds the PTO3GPP with YUV420 pictures.
* @note This function is given to the PTO3GPP in the M4PTO3GPP_Params structure
* @param pContext (IN) The integrator own context
* @param pImagePlanes(IN/OUT) Pointer to an array of three valid image planes
* @param pPictureDuration(OUT) Duration of the returned picture
*
* @return M4NO_ERROR: No error
* @return M4PTO3GPP_WAR_LAST_PICTURE: The returned image is the last one
* @return M4ERR_PARAMETER: At least one of the function parameters is null
******************************************************************************
*/
M4OSA_ERR M4xVSS_PictureCallbackFct(M4OSA_Void* pPictureCtxt, M4VIFI_ImagePlane* pImagePlanes,
M4OSA_Double* pPictureDuration)
{
M4OSA_ERR err = M4NO_ERROR;
M4OSA_UInt8 last_frame_flag = 0;
M4xVSS_PictureCallbackCtxt* pC = (M4xVSS_PictureCallbackCtxt*) (pPictureCtxt);
/*Used for pan&zoom*/
M4OSA_UInt8 tempPanzoomXa = 0;
M4OSA_UInt8 tempPanzoomXb = 0;
M4AIR_Params Params;
/**/
/*Used for cropping and black borders*/
M4OSA_Context pPictureContext = M4OSA_NULL;
M4OSA_FilePosition pictureSize = 0 ;
M4OSA_UInt8* pictureBuffer = M4OSA_NULL;
//M4EXIFC_Context pExifContext = M4OSA_NULL;
M4EXIFC_BasicTags pBasicTags;
M4VIFI_ImagePlane pImagePlanes1 = pImagePlanes[0];
M4VIFI_ImagePlane pImagePlanes2 = pImagePlanes[1];
M4VIFI_ImagePlane pImagePlanes3 = pImagePlanes[2];
/**/
/**
* Check input parameters */
M4OSA_DEBUG_IF2((M4OSA_NULL==pPictureCtxt), M4ERR_PARAMETER,
"M4xVSS_PictureCallbackFct: pPictureCtxt is M4OSA_NULL");
M4OSA_DEBUG_IF2((M4OSA_NULL==pImagePlanes), M4ERR_PARAMETER,
"M4xVSS_PictureCallbackFct: pImagePlanes is M4OSA_NULL");
M4OSA_DEBUG_IF2((M4OSA_NULL==pPictureDuration), M4ERR_PARAMETER,
"M4xVSS_PictureCallbackFct: pPictureDuration is M4OSA_NULL");
M4OSA_TRACE1_0("M4xVSS_PictureCallbackFct :Entering");
/*PR P4ME00003181 In case the image number is 0, pan&zoom can not be used*/
if(M4OSA_TRUE == pC->m_pPto3GPPparams->isPanZoom && pC->m_NbImage == 0)
{
pC->m_pPto3GPPparams->isPanZoom = M4OSA_FALSE;
}
/*If no cropping/black borders or pan&zoom, just decode and resize the picture*/
if(pC->m_mediaRendering == M4xVSS_kResizing && M4OSA_FALSE == pC->m_pPto3GPPparams->isPanZoom)
{
/**
* Convert and resize input ARGB8888 file to YUV420 */
/*To support ARGB8888 : */
M4OSA_TRACE1_2("M4xVSS_PictureCallbackFct 1: width and heght %d %d",
pC->m_pPto3GPPparams->width,pC->m_pPto3GPPparams->height);
err = M4xVSS_internalConvertAndResizeARGB8888toYUV420(pC->m_FileIn,
pC->m_pFileReadPtr, pImagePlanes,pC->m_pPto3GPPparams->width,
pC->m_pPto3GPPparams->height);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_PictureCallbackFct: Error when decoding JPEG: 0x%x\n", err);
return err;
}
}
/*In case of cropping, black borders or pan&zoom, call the EXIF reader and the AIR*/
else
{
/**
* Computes ratios */
if(pC->m_pDecodedPlane == M4OSA_NULL)
{
/**
* Convert input ARGB8888 file to YUV420 */
M4OSA_TRACE1_2("M4xVSS_PictureCallbackFct 2: width and heght %d %d",
pC->m_pPto3GPPparams->width,pC->m_pPto3GPPparams->height);
err = M4xVSS_internalConvertARGB8888toYUV420(pC->m_FileIn, pC->m_pFileReadPtr,
&(pC->m_pDecodedPlane),pC->m_pPto3GPPparams->width,pC->m_pPto3GPPparams->height);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_PictureCallbackFct: Error when decoding JPEG: 0x%x\n", err);
if(pC->m_pDecodedPlane != M4OSA_NULL)
{
/* YUV420 planar is returned but allocation is made only once
(contigous planes in memory) */
if(pC->m_pDecodedPlane->pac_data != M4OSA_NULL)
{
free(pC->m_pDecodedPlane->pac_data);
}
free(pC->m_pDecodedPlane);
pC->m_pDecodedPlane = M4OSA_NULL;
}
return err;
}
}
/*Initialize AIR Params*/
Params.m_inputCoord.m_x = 0;
Params.m_inputCoord.m_y = 0;
Params.m_inputSize.m_height = pC->m_pDecodedPlane->u_height;
Params.m_inputSize.m_width = pC->m_pDecodedPlane->u_width;
Params.m_outputSize.m_width = pImagePlanes->u_width;
Params.m_outputSize.m_height = pImagePlanes->u_height;
Params.m_bOutputStripe = M4OSA_FALSE;
Params.m_outputOrientation = M4COMMON_kOrientationTopLeft;
/*Initialize Exif params structure*/
pBasicTags.orientation = M4COMMON_kOrientationUnknown;
/**
Pan&zoom params*/
if(M4OSA_TRUE == pC->m_pPto3GPPparams->isPanZoom)
{
/*Save ratio values, they can be reused if the new ratios are 0*/
tempPanzoomXa = (M4OSA_UInt8)pC->m_pPto3GPPparams->PanZoomXa;
tempPanzoomXb = (M4OSA_UInt8)pC->m_pPto3GPPparams->PanZoomXb;
/*Check that the ratio is not 0*/
/*Check (a) parameters*/
if(pC->m_pPto3GPPparams->PanZoomXa == 0)
{
M4OSA_UInt8 maxRatio = 0;
if(pC->m_pPto3GPPparams->PanZoomTopleftXa >=
pC->m_pPto3GPPparams->PanZoomTopleftYa)
{
/*The ratio is 0, that means the area of the picture defined with (a)
parameters is bigger than the image size*/
if(pC->m_pPto3GPPparams->PanZoomTopleftXa + tempPanzoomXa > 1000)
{
/*The oversize is maxRatio*/
maxRatio = pC->m_pPto3GPPparams->PanZoomTopleftXa + tempPanzoomXa - 1000;
}
}
else
{
/*The ratio is 0, that means the area of the picture defined with (a)
parameters is bigger than the image size*/
if(pC->m_pPto3GPPparams->PanZoomTopleftYa + tempPanzoomXa > 1000)
{
/*The oversize is maxRatio*/
maxRatio = pC->m_pPto3GPPparams->PanZoomTopleftYa + tempPanzoomXa - 1000;
}
}
/*Modify the (a) parameters:*/
if(pC->m_pPto3GPPparams->PanZoomTopleftXa >= maxRatio)
{
/*The (a) topleft parameters can be moved to keep the same area size*/
pC->m_pPto3GPPparams->PanZoomTopleftXa -= maxRatio;
}
else
{
/*Move the (a) topleft parameter to 0 but the ratio will be also further
modified to match the image size*/
pC->m_pPto3GPPparams->PanZoomTopleftXa = 0;
}
if(pC->m_pPto3GPPparams->PanZoomTopleftYa >= maxRatio)
{
/*The (a) topleft parameters can be moved to keep the same area size*/
pC->m_pPto3GPPparams->PanZoomTopleftYa -= maxRatio;
}
else
{
/*Move the (a) topleft parameter to 0 but the ratio will be also further
modified to match the image size*/
pC->m_pPto3GPPparams->PanZoomTopleftYa = 0;
}
/*The new ratio is the original one*/
pC->m_pPto3GPPparams->PanZoomXa = tempPanzoomXa;
if(pC->m_pPto3GPPparams->PanZoomXa + pC->m_pPto3GPPparams->PanZoomTopleftXa > 1000)
{
/*Change the ratio if the area of the picture defined with (a) parameters is
bigger than the image size*/
pC->m_pPto3GPPparams->PanZoomXa = 1000 - pC->m_pPto3GPPparams->PanZoomTopleftXa;
}
if(pC->m_pPto3GPPparams->PanZoomXa + pC->m_pPto3GPPparams->PanZoomTopleftYa > 1000)
{
/*Change the ratio if the area of the picture defined with (a) parameters is
bigger than the image size*/
pC->m_pPto3GPPparams->PanZoomXa = 1000 - pC->m_pPto3GPPparams->PanZoomTopleftYa;
}
}
/*Check (b) parameters*/
if(pC->m_pPto3GPPparams->PanZoomXb == 0)
{
M4OSA_UInt8 maxRatio = 0;
if(pC->m_pPto3GPPparams->PanZoomTopleftXb >=
pC->m_pPto3GPPparams->PanZoomTopleftYb)
{
/*The ratio is 0, that means the area of the picture defined with (b)
parameters is bigger than the image size*/
if(pC->m_pPto3GPPparams->PanZoomTopleftXb + tempPanzoomXb > 1000)
{
/*The oversize is maxRatio*/
maxRatio = pC->m_pPto3GPPparams->PanZoomTopleftXb + tempPanzoomXb - 1000;
}
}
else
{
/*The ratio is 0, that means the area of the picture defined with (b)
parameters is bigger than the image size*/
if(pC->m_pPto3GPPparams->PanZoomTopleftYb + tempPanzoomXb > 1000)
{
/*The oversize is maxRatio*/
maxRatio = pC->m_pPto3GPPparams->PanZoomTopleftYb + tempPanzoomXb - 1000;
}
}
/*Modify the (b) parameters:*/
if(pC->m_pPto3GPPparams->PanZoomTopleftXb >= maxRatio)
{
/*The (b) topleft parameters can be moved to keep the same area size*/
pC->m_pPto3GPPparams->PanZoomTopleftXb -= maxRatio;
}
else
{
/*Move the (b) topleft parameter to 0 but the ratio will be also further
modified to match the image size*/
pC->m_pPto3GPPparams->PanZoomTopleftXb = 0;
}
if(pC->m_pPto3GPPparams->PanZoomTopleftYb >= maxRatio)
{
/*The (b) topleft parameters can be moved to keep the same area size*/
pC->m_pPto3GPPparams->PanZoomTopleftYb -= maxRatio;
}
else
{
/*Move the (b) topleft parameter to 0 but the ratio will be also further
modified to match the image size*/
pC->m_pPto3GPPparams->PanZoomTopleftYb = 0;
}
/*The new ratio is the original one*/
pC->m_pPto3GPPparams->PanZoomXb = tempPanzoomXb;
if(pC->m_pPto3GPPparams->PanZoomXb + pC->m_pPto3GPPparams->PanZoomTopleftXb > 1000)
{
/*Change the ratio if the area of the picture defined with (b) parameters is
bigger than the image size*/
pC->m_pPto3GPPparams->PanZoomXb = 1000 - pC->m_pPto3GPPparams->PanZoomTopleftXb;
}
if(pC->m_pPto3GPPparams->PanZoomXb + pC->m_pPto3GPPparams->PanZoomTopleftYb > 1000)
{
/*Change the ratio if the area of the picture defined with (b) parameters is
bigger than the image size*/
pC->m_pPto3GPPparams->PanZoomXb = 1000 - pC->m_pPto3GPPparams->PanZoomTopleftYb;
}
}
/**
* Computes AIR parameters */
/* Params.m_inputCoord.m_x = (M4OSA_UInt32)(pC->m_pDecodedPlane->u_width *
(pC->m_pPto3GPPparams->PanZoomTopleftXa +
(M4OSA_Int16)((pC->m_pPto3GPPparams->PanZoomTopleftXb \
- pC->m_pPto3GPPparams->PanZoomTopleftXa) *
pC->m_ImageCounter) / (M4OSA_Double)pC->m_NbImage)) / 100;
Params.m_inputCoord.m_y = (M4OSA_UInt32)(pC->m_pDecodedPlane->u_height *
(pC->m_pPto3GPPparams->PanZoomTopleftYa +
(M4OSA_Int16)((pC->m_pPto3GPPparams->PanZoomTopleftYb\
- pC->m_pPto3GPPparams->PanZoomTopleftYa) *
pC->m_ImageCounter) / (M4OSA_Double)pC->m_NbImage)) / 100;
Params.m_inputSize.m_width = (M4OSA_UInt32)(pC->m_pDecodedPlane->u_width *
(pC->m_pPto3GPPparams->PanZoomXa +
(M4OSA_Int16)((pC->m_pPto3GPPparams->PanZoomXb - pC->m_pPto3GPPparams->PanZoomXa) *
pC->m_ImageCounter) / (M4OSA_Double)pC->m_NbImage)) / 100;
Params.m_inputSize.m_height = (M4OSA_UInt32)(pC->m_pDecodedPlane->u_height *
(pC->m_pPto3GPPparams->PanZoomXa +
(M4OSA_Int16)((pC->m_pPto3GPPparams->PanZoomXb - pC->m_pPto3GPPparams->PanZoomXa) *
pC->m_ImageCounter) / (M4OSA_Double)pC->m_NbImage)) / 100;
*/
// Instead of using pC->m_NbImage we have to use (pC->m_NbImage-1) as pC->m_ImageCounter
// will be x-1 max for x no. of frames
Params.m_inputCoord.m_x = (M4OSA_UInt32)((((M4OSA_Double)pC->m_pDecodedPlane->u_width *
(pC->m_pPto3GPPparams->PanZoomTopleftXa +
(M4OSA_Double)((M4OSA_Double)(pC->m_pPto3GPPparams->PanZoomTopleftXb\
- pC->m_pPto3GPPparams->PanZoomTopleftXa) *
pC->m_ImageCounter) / (M4OSA_Double)pC->m_NbImage-1)) / 1000));
Params.m_inputCoord.m_y =
(M4OSA_UInt32)((((M4OSA_Double)pC->m_pDecodedPlane->u_height *
(pC->m_pPto3GPPparams->PanZoomTopleftYa +
(M4OSA_Double)((M4OSA_Double)(pC->m_pPto3GPPparams->PanZoomTopleftYb\
- pC->m_pPto3GPPparams->PanZoomTopleftYa) *
pC->m_ImageCounter) / (M4OSA_Double)pC->m_NbImage-1)) / 1000));
Params.m_inputSize.m_width =
(M4OSA_UInt32)((((M4OSA_Double)pC->m_pDecodedPlane->u_width *
(pC->m_pPto3GPPparams->PanZoomXa +
(M4OSA_Double)((M4OSA_Double)(pC->m_pPto3GPPparams->PanZoomXb\
- pC->m_pPto3GPPparams->PanZoomXa) *
pC->m_ImageCounter) / (M4OSA_Double)pC->m_NbImage-1)) / 1000));
Params.m_inputSize.m_height =
(M4OSA_UInt32)((((M4OSA_Double)pC->m_pDecodedPlane->u_height *
(pC->m_pPto3GPPparams->PanZoomXa +
(M4OSA_Double)((M4OSA_Double)(pC->m_pPto3GPPparams->PanZoomXb \
- pC->m_pPto3GPPparams->PanZoomXa) *
pC->m_ImageCounter) / (M4OSA_Double)pC->m_NbImage-1)) / 1000));
if((Params.m_inputSize.m_width + Params.m_inputCoord.m_x)\
> pC->m_pDecodedPlane->u_width)
{
Params.m_inputSize.m_width = pC->m_pDecodedPlane->u_width \
- Params.m_inputCoord.m_x;
}
if((Params.m_inputSize.m_height + Params.m_inputCoord.m_y)\
> pC->m_pDecodedPlane->u_height)
{
Params.m_inputSize.m_height = pC->m_pDecodedPlane->u_height\
- Params.m_inputCoord.m_y;
}
Params.m_inputSize.m_width = (Params.m_inputSize.m_width>>1)<<1;
Params.m_inputSize.m_height = (Params.m_inputSize.m_height>>1)<<1;
}
/**
Picture rendering: Black borders*/
if(pC->m_mediaRendering == M4xVSS_kBlackBorders)
{
memset((void *)pImagePlanes[0].pac_data,Y_PLANE_BORDER_VALUE,
(pImagePlanes[0].u_height*pImagePlanes[0].u_stride));
memset((void *)pImagePlanes[1].pac_data,U_PLANE_BORDER_VALUE,
(pImagePlanes[1].u_height*pImagePlanes[1].u_stride));
memset((void *)pImagePlanes[2].pac_data,V_PLANE_BORDER_VALUE,
(pImagePlanes[2].u_height*pImagePlanes[2].u_stride));
/**
First without pan&zoom*/
if(M4OSA_FALSE == pC->m_pPto3GPPparams->isPanZoom)
{
switch(pBasicTags.orientation)
{
default:
case M4COMMON_kOrientationUnknown:
Params.m_outputOrientation = M4COMMON_kOrientationTopLeft;
case M4COMMON_kOrientationTopLeft:
case M4COMMON_kOrientationTopRight:
case M4COMMON_kOrientationBottomRight:
case M4COMMON_kOrientationBottomLeft:
if((M4OSA_UInt32)((pC->m_pDecodedPlane->u_height * pImagePlanes->u_width)\
/pC->m_pDecodedPlane->u_width) <= pImagePlanes->u_height)
//Params.m_inputSize.m_height < Params.m_inputSize.m_width)
{
/*it is height so black borders will be on the top and on the bottom side*/
Params.m_outputSize.m_width = pImagePlanes->u_width;
Params.m_outputSize.m_height =
(M4OSA_UInt32)((pC->m_pDecodedPlane->u_height \
* pImagePlanes->u_width) /pC->m_pDecodedPlane->u_width);
/*number of lines at the top*/
pImagePlanes[0].u_topleft =
(M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[0].u_height\
-Params.m_outputSize.m_height)>>1))*pImagePlanes[0].u_stride;
pImagePlanes[0].u_height = Params.m_outputSize.m_height;
pImagePlanes[1].u_topleft =
(M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[1].u_height\
-(Params.m_outputSize.m_height>>1)))>>1)*pImagePlanes[1].u_stride;
pImagePlanes[1].u_height = Params.m_outputSize.m_height>>1;
pImagePlanes[2].u_topleft =
(M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[2].u_height\
-(Params.m_outputSize.m_height>>1)))>>1)*pImagePlanes[2].u_stride;
pImagePlanes[2].u_height = Params.m_outputSize.m_height>>1;
}
else
{
/*it is width so black borders will be on the left and right side*/
Params.m_outputSize.m_height = pImagePlanes->u_height;
Params.m_outputSize.m_width =
(M4OSA_UInt32)((pC->m_pDecodedPlane->u_width \
* pImagePlanes->u_height) /pC->m_pDecodedPlane->u_height);
pImagePlanes[0].u_topleft =
(M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[0].u_width\
-Params.m_outputSize.m_width)>>1));
pImagePlanes[0].u_width = Params.m_outputSize.m_width;
pImagePlanes[1].u_topleft =
(M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[1].u_width\
-(Params.m_outputSize.m_width>>1)))>>1);
pImagePlanes[1].u_width = Params.m_outputSize.m_width>>1;
pImagePlanes[2].u_topleft =
(M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[2].u_width\
-(Params.m_outputSize.m_width>>1)))>>1);
pImagePlanes[2].u_width = Params.m_outputSize.m_width>>1;
}
break;
case M4COMMON_kOrientationLeftTop:
case M4COMMON_kOrientationLeftBottom:
case M4COMMON_kOrientationRightTop:
case M4COMMON_kOrientationRightBottom:
if((M4OSA_UInt32)((pC->m_pDecodedPlane->u_width * pImagePlanes->u_width)\
/pC->m_pDecodedPlane->u_height) < pImagePlanes->u_height)
//Params.m_inputSize.m_height > Params.m_inputSize.m_width)
{
/*it is height so black borders will be on the top and on
the bottom side*/
Params.m_outputSize.m_height = pImagePlanes->u_width;
Params.m_outputSize.m_width =
(M4OSA_UInt32)((pC->m_pDecodedPlane->u_width \
* pImagePlanes->u_width) /pC->m_pDecodedPlane->u_height);
/*number of lines at the top*/
pImagePlanes[0].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[0].u_height\
-Params.m_outputSize.m_width))>>1)*pImagePlanes[0].u_stride)+1;
pImagePlanes[0].u_height = Params.m_outputSize.m_width;
pImagePlanes[1].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[1].u_height\
-(Params.m_outputSize.m_width>>1)))>>1)\
*pImagePlanes[1].u_stride)+1;
pImagePlanes[1].u_height = Params.m_outputSize.m_width>>1;
pImagePlanes[2].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[2].u_height\
-(Params.m_outputSize.m_width>>1)))>>1)\
*pImagePlanes[2].u_stride)+1;
pImagePlanes[2].u_height = Params.m_outputSize.m_width>>1;
}
else
{
/*it is width so black borders will be on the left and right side*/
Params.m_outputSize.m_width = pImagePlanes->u_height;
Params.m_outputSize.m_height =
(M4OSA_UInt32)((pC->m_pDecodedPlane->u_height\
* pImagePlanes->u_height) /pC->m_pDecodedPlane->u_width);
pImagePlanes[0].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[0].u_width\
-Params.m_outputSize.m_height))>>1))+1;
pImagePlanes[0].u_width = Params.m_outputSize.m_height;
pImagePlanes[1].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[1].u_width\
-(Params.m_outputSize.m_height>>1)))>>1))+1;
pImagePlanes[1].u_width = Params.m_outputSize.m_height>>1;
pImagePlanes[2].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[2].u_width\
-(Params.m_outputSize.m_height>>1)))>>1))+1;
pImagePlanes[2].u_width = Params.m_outputSize.m_height>>1;
}
break;
}
}
/**
Secondly with pan&zoom*/
else
{
switch(pBasicTags.orientation)
{
default:
case M4COMMON_kOrientationUnknown:
Params.m_outputOrientation = M4COMMON_kOrientationTopLeft;
case M4COMMON_kOrientationTopLeft:
case M4COMMON_kOrientationTopRight:
case M4COMMON_kOrientationBottomRight:
case M4COMMON_kOrientationBottomLeft:
/*NO ROTATION*/
if((M4OSA_UInt32)((pC->m_pDecodedPlane->u_height * pImagePlanes->u_width)\
/pC->m_pDecodedPlane->u_width) <= pImagePlanes->u_height)
//Params.m_inputSize.m_height < Params.m_inputSize.m_width)
{
/*Black borders will be on the top and bottom of the output video*/
/*Maximum output height if the input image aspect ratio is kept and if
the output width is the screen width*/
M4OSA_UInt32 tempOutputSizeHeight =
(M4OSA_UInt32)((pC->m_pDecodedPlane->u_height\
* pImagePlanes->u_width) /pC->m_pDecodedPlane->u_width);
M4OSA_UInt32 tempInputSizeHeightMax = 0;
M4OSA_UInt32 tempFinalInputHeight = 0;
/*The output width is the screen width*/
Params.m_outputSize.m_width = pImagePlanes->u_width;
tempOutputSizeHeight = (tempOutputSizeHeight>>1)<<1;
/*Maximum input height according to the maximum output height
(proportional to the maximum output height)*/
tempInputSizeHeightMax = (pImagePlanes->u_height\
*Params.m_inputSize.m_height)/tempOutputSizeHeight;
tempInputSizeHeightMax = (tempInputSizeHeightMax>>1)<<1;
/*Check if the maximum possible input height is contained into the
input image height*/
if(tempInputSizeHeightMax <= pC->m_pDecodedPlane->u_height)
{
/*The maximum possible input height is contained in the input
image height,
that means no black borders, the input pan zoom area will be extended
so that the input AIR height will be the maximum possible*/
if(((tempInputSizeHeightMax - Params.m_inputSize.m_height)>>1)\
<= Params.m_inputCoord.m_y
&& ((tempInputSizeHeightMax - Params.m_inputSize.m_height)>>1)\
<= pC->m_pDecodedPlane->u_height -(Params.m_inputCoord.m_y\
+ Params.m_inputSize.m_height))
{
/*The input pan zoom area can be extended symmetrically on the
top and bottom side*/
Params.m_inputCoord.m_y -= ((tempInputSizeHeightMax \
- Params.m_inputSize.m_height)>>1);
}
else if(Params.m_inputCoord.m_y < pC->m_pDecodedPlane->u_height\
-(Params.m_inputCoord.m_y + Params.m_inputSize.m_height))
{
/*There is not enough place above the input pan zoom area to
extend it symmetrically,
so extend it to the maximum on the top*/
Params.m_inputCoord.m_y = 0;
}
else
{
/*There is not enough place below the input pan zoom area to
extend it symmetrically,
so extend it to the maximum on the bottom*/
Params.m_inputCoord.m_y = pC->m_pDecodedPlane->u_height \
- tempInputSizeHeightMax;
}
/*The input height of the AIR is the maximum possible height*/
Params.m_inputSize.m_height = tempInputSizeHeightMax;
}
else
{
/*The maximum possible input height is greater than the input
image height,
that means black borders are necessary to keep aspect ratio
The input height of the AIR is all the input image height*/
Params.m_outputSize.m_height =
(tempOutputSizeHeight*pC->m_pDecodedPlane->u_height)\
/Params.m_inputSize.m_height;
Params.m_outputSize.m_height = (Params.m_outputSize.m_height>>1)<<1;
Params.m_inputCoord.m_y = 0;
Params.m_inputSize.m_height = pC->m_pDecodedPlane->u_height;
pImagePlanes[0].u_topleft =
(M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[0].u_height\
-Params.m_outputSize.m_height)>>1))*pImagePlanes[0].u_stride;
pImagePlanes[0].u_height = Params.m_outputSize.m_height;
pImagePlanes[1].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[1].u_height\
-(Params.m_outputSize.m_height>>1)))>>1)\
*pImagePlanes[1].u_stride);
pImagePlanes[1].u_height = Params.m_outputSize.m_height>>1;
pImagePlanes[2].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[2].u_height\
-(Params.m_outputSize.m_height>>1)))>>1)\
*pImagePlanes[2].u_stride);
pImagePlanes[2].u_height = Params.m_outputSize.m_height>>1;
}
}
else
{
/*Black borders will be on the left and right side of the output video*/
/*Maximum output width if the input image aspect ratio is kept and if the
output height is the screen height*/
M4OSA_UInt32 tempOutputSizeWidth =
(M4OSA_UInt32)((pC->m_pDecodedPlane->u_width \
* pImagePlanes->u_height) /pC->m_pDecodedPlane->u_height);
M4OSA_UInt32 tempInputSizeWidthMax = 0;
M4OSA_UInt32 tempFinalInputWidth = 0;
/*The output height is the screen height*/
Params.m_outputSize.m_height = pImagePlanes->u_height;
tempOutputSizeWidth = (tempOutputSizeWidth>>1)<<1;
/*Maximum input width according to the maximum output width
(proportional to the maximum output width)*/
tempInputSizeWidthMax =
(pImagePlanes->u_width*Params.m_inputSize.m_width)\
/tempOutputSizeWidth;
tempInputSizeWidthMax = (tempInputSizeWidthMax>>1)<<1;
/*Check if the maximum possible input width is contained into the input
image width*/
if(tempInputSizeWidthMax <= pC->m_pDecodedPlane->u_width)
{
/*The maximum possible input width is contained in the input
image width,
that means no black borders, the input pan zoom area will be extended
so that the input AIR width will be the maximum possible*/
if(((tempInputSizeWidthMax - Params.m_inputSize.m_width)>>1) \
<= Params.m_inputCoord.m_x
&& ((tempInputSizeWidthMax - Params.m_inputSize.m_width)>>1)\
<= pC->m_pDecodedPlane->u_width -(Params.m_inputCoord.m_x \
+ Params.m_inputSize.m_width))
{
/*The input pan zoom area can be extended symmetrically on the
right and left side*/
Params.m_inputCoord.m_x -= ((tempInputSizeWidthMax\
- Params.m_inputSize.m_width)>>1);
}
else if(Params.m_inputCoord.m_x < pC->m_pDecodedPlane->u_width\
-(Params.m_inputCoord.m_x + Params.m_inputSize.m_width))
{
/*There is not enough place above the input pan zoom area to
extend it symmetrically,
so extend it to the maximum on the left*/
Params.m_inputCoord.m_x = 0;
}
else
{
/*There is not enough place below the input pan zoom area
to extend it symmetrically,
so extend it to the maximum on the right*/
Params.m_inputCoord.m_x = pC->m_pDecodedPlane->u_width \
- tempInputSizeWidthMax;
}
/*The input width of the AIR is the maximum possible width*/
Params.m_inputSize.m_width = tempInputSizeWidthMax;
}
else
{
/*The maximum possible input width is greater than the input
image width,
that means black borders are necessary to keep aspect ratio
The input width of the AIR is all the input image width*/
Params.m_outputSize.m_width =\
(tempOutputSizeWidth*pC->m_pDecodedPlane->u_width)\
/Params.m_inputSize.m_width;
Params.m_outputSize.m_width = (Params.m_outputSize.m_width>>1)<<1;
Params.m_inputCoord.m_x = 0;
Params.m_inputSize.m_width = pC->m_pDecodedPlane->u_width;
pImagePlanes[0].u_topleft =
(M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[0].u_width\
-Params.m_outputSize.m_width)>>1));
pImagePlanes[0].u_width = Params.m_outputSize.m_width;
pImagePlanes[1].u_topleft =
(M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[1].u_width\
-(Params.m_outputSize.m_width>>1)))>>1);
pImagePlanes[1].u_width = Params.m_outputSize.m_width>>1;
pImagePlanes[2].u_topleft =
(M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[2].u_width\
-(Params.m_outputSize.m_width>>1)))>>1);
pImagePlanes[2].u_width = Params.m_outputSize.m_width>>1;
}
}
break;
case M4COMMON_kOrientationLeftTop:
case M4COMMON_kOrientationLeftBottom:
case M4COMMON_kOrientationRightTop:
case M4COMMON_kOrientationRightBottom:
/*ROTATION*/
if((M4OSA_UInt32)((pC->m_pDecodedPlane->u_width * pImagePlanes->u_width)\
/pC->m_pDecodedPlane->u_height) < pImagePlanes->u_height)
//Params.m_inputSize.m_height > Params.m_inputSize.m_width)
{
/*Black borders will be on the left and right side of the output video*/
/*Maximum output height if the input image aspect ratio is kept and if
the output height is the screen width*/
M4OSA_UInt32 tempOutputSizeHeight =
(M4OSA_UInt32)((pC->m_pDecodedPlane->u_width * pImagePlanes->u_width)\
/pC->m_pDecodedPlane->u_height);
M4OSA_UInt32 tempInputSizeHeightMax = 0;
M4OSA_UInt32 tempFinalInputHeight = 0;
/*The output width is the screen height*/
Params.m_outputSize.m_height = pImagePlanes->u_width;
Params.m_outputSize.m_width= pImagePlanes->u_height;
tempOutputSizeHeight = (tempOutputSizeHeight>>1)<<1;
/*Maximum input height according to the maximum output height
(proportional to the maximum output height)*/
tempInputSizeHeightMax =
(pImagePlanes->u_height*Params.m_inputSize.m_width)\
/tempOutputSizeHeight;
tempInputSizeHeightMax = (tempInputSizeHeightMax>>1)<<1;
/*Check if the maximum possible input height is contained into the
input image width (rotation included)*/
if(tempInputSizeHeightMax <= pC->m_pDecodedPlane->u_width)
{
/*The maximum possible input height is contained in the input
image width (rotation included),
that means no black borders, the input pan zoom area will be extended
so that the input AIR width will be the maximum possible*/
if(((tempInputSizeHeightMax - Params.m_inputSize.m_width)>>1) \
<= Params.m_inputCoord.m_x
&& ((tempInputSizeHeightMax - Params.m_inputSize.m_width)>>1)\
<= pC->m_pDecodedPlane->u_width -(Params.m_inputCoord.m_x \
+ Params.m_inputSize.m_width))
{
/*The input pan zoom area can be extended symmetrically on the
right and left side*/
Params.m_inputCoord.m_x -= ((tempInputSizeHeightMax \
- Params.m_inputSize.m_width)>>1);
}
else if(Params.m_inputCoord.m_x < pC->m_pDecodedPlane->u_width\
-(Params.m_inputCoord.m_x + Params.m_inputSize.m_width))
{
/*There is not enough place on the left of the input pan
zoom area to extend it symmetrically,
so extend it to the maximum on the left*/
Params.m_inputCoord.m_x = 0;
}
else
{
/*There is not enough place on the right of the input pan zoom
area to extend it symmetrically,
so extend it to the maximum on the right*/
Params.m_inputCoord.m_x =
pC->m_pDecodedPlane->u_width - tempInputSizeHeightMax;
}
/*The input width of the AIR is the maximum possible width*/
Params.m_inputSize.m_width = tempInputSizeHeightMax;
}
else
{
/*The maximum possible input height is greater than the input
image width (rotation included),
that means black borders are necessary to keep aspect ratio
The input width of the AIR is all the input image width*/
Params.m_outputSize.m_width =
(tempOutputSizeHeight*pC->m_pDecodedPlane->u_width)\
/Params.m_inputSize.m_width;
Params.m_outputSize.m_width = (Params.m_outputSize.m_width>>1)<<1;
Params.m_inputCoord.m_x = 0;
Params.m_inputSize.m_width = pC->m_pDecodedPlane->u_width;
pImagePlanes[0].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[0].u_height\
-Params.m_outputSize.m_width))>>1)*pImagePlanes[0].u_stride)+1;
pImagePlanes[0].u_height = Params.m_outputSize.m_width;
pImagePlanes[1].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[1].u_height\
-(Params.m_outputSize.m_width>>1)))>>1)\
*pImagePlanes[1].u_stride)+1;
pImagePlanes[1].u_height = Params.m_outputSize.m_width>>1;
pImagePlanes[2].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[2].u_height\
-(Params.m_outputSize.m_width>>1)))>>1)\
*pImagePlanes[2].u_stride)+1;
pImagePlanes[2].u_height = Params.m_outputSize.m_width>>1;
}
}
else
{
/*Black borders will be on the top and bottom of the output video*/
/*Maximum output width if the input image aspect ratio is kept and if
the output width is the screen height*/
M4OSA_UInt32 tempOutputSizeWidth =
(M4OSA_UInt32)((pC->m_pDecodedPlane->u_height * pImagePlanes->u_height)\
/pC->m_pDecodedPlane->u_width);
M4OSA_UInt32 tempInputSizeWidthMax = 0;
M4OSA_UInt32 tempFinalInputWidth = 0, tempFinalOutputWidth = 0;
/*The output height is the screen width*/
Params.m_outputSize.m_width = pImagePlanes->u_height;
Params.m_outputSize.m_height= pImagePlanes->u_width;
tempOutputSizeWidth = (tempOutputSizeWidth>>1)<<1;
/*Maximum input width according to the maximum output width
(proportional to the maximum output width)*/
tempInputSizeWidthMax =
(pImagePlanes->u_width*Params.m_inputSize.m_height)/tempOutputSizeWidth;
tempInputSizeWidthMax = (tempInputSizeWidthMax>>1)<<1;
/*Check if the maximum possible input width is contained into the input
image height (rotation included)*/
if(tempInputSizeWidthMax <= pC->m_pDecodedPlane->u_height)
{
/*The maximum possible input width is contained in the input
image height (rotation included),
that means no black borders, the input pan zoom area will be extended
so that the input AIR height will be the maximum possible*/
if(((tempInputSizeWidthMax - Params.m_inputSize.m_height)>>1) \
<= Params.m_inputCoord.m_y
&& ((tempInputSizeWidthMax - Params.m_inputSize.m_height)>>1)\
<= pC->m_pDecodedPlane->u_height -(Params.m_inputCoord.m_y \
+ Params.m_inputSize.m_height))
{
/*The input pan zoom area can be extended symmetrically on
the right and left side*/
Params.m_inputCoord.m_y -= ((tempInputSizeWidthMax \
- Params.m_inputSize.m_height)>>1);
}
else if(Params.m_inputCoord.m_y < pC->m_pDecodedPlane->u_height\
-(Params.m_inputCoord.m_y + Params.m_inputSize.m_height))
{
/*There is not enough place on the top of the input pan zoom
area to extend it symmetrically,
so extend it to the maximum on the top*/
Params.m_inputCoord.m_y = 0;
}
else
{
/*There is not enough place on the bottom of the input pan zoom
area to extend it symmetrically,
so extend it to the maximum on the bottom*/
Params.m_inputCoord.m_y = pC->m_pDecodedPlane->u_height\
- tempInputSizeWidthMax;
}
/*The input height of the AIR is the maximum possible height*/
Params.m_inputSize.m_height = tempInputSizeWidthMax;
}
else
{
/*The maximum possible input width is greater than the input\
image height (rotation included),
that means black borders are necessary to keep aspect ratio
The input height of the AIR is all the input image height*/
Params.m_outputSize.m_height =
(tempOutputSizeWidth*pC->m_pDecodedPlane->u_height)\
/Params.m_inputSize.m_height;
Params.m_outputSize.m_height = (Params.m_outputSize.m_height>>1)<<1;
Params.m_inputCoord.m_y = 0;
Params.m_inputSize.m_height = pC->m_pDecodedPlane->u_height;
pImagePlanes[0].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[0].u_width\
-Params.m_outputSize.m_height))>>1))+1;
pImagePlanes[0].u_width = Params.m_outputSize.m_height;
pImagePlanes[1].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[1].u_width\
-(Params.m_outputSize.m_height>>1)))>>1))+1;
pImagePlanes[1].u_width = Params.m_outputSize.m_height>>1;
pImagePlanes[2].u_topleft =
((M4xVSS_ABS((M4OSA_Int32)(pImagePlanes[2].u_width\
-(Params.m_outputSize.m_height>>1)))>>1))+1;
pImagePlanes[2].u_width = Params.m_outputSize.m_height>>1;
}
}
break;
}
}
/*Width and height have to be even*/
Params.m_outputSize.m_width = (Params.m_outputSize.m_width>>1)<<1;
Params.m_outputSize.m_height = (Params.m_outputSize.m_height>>1)<<1;
Params.m_inputSize.m_width = (Params.m_inputSize.m_width>>1)<<1;
Params.m_inputSize.m_height = (Params.m_inputSize.m_height>>1)<<1;
pImagePlanes[0].u_width = (pImagePlanes[0].u_width>>1)<<1;
pImagePlanes[1].u_width = (pImagePlanes[1].u_width>>1)<<1;
pImagePlanes[2].u_width = (pImagePlanes[2].u_width>>1)<<1;
pImagePlanes[0].u_height = (pImagePlanes[0].u_height>>1)<<1;
pImagePlanes[1].u_height = (pImagePlanes[1].u_height>>1)<<1;
pImagePlanes[2].u_height = (pImagePlanes[2].u_height>>1)<<1;
/*Check that values are coherent*/
if(Params.m_inputSize.m_height == Params.m_outputSize.m_height)
{
Params.m_inputSize.m_width = Params.m_outputSize.m_width;
}
else if(Params.m_inputSize.m_width == Params.m_outputSize.m_width)
{
Params.m_inputSize.m_height = Params.m_outputSize.m_height;
}
}
/**
Picture rendering: Resizing and Cropping*/
if(pC->m_mediaRendering != M4xVSS_kBlackBorders)
{
switch(pBasicTags.orientation)
{
default:
case M4COMMON_kOrientationUnknown:
Params.m_outputOrientation = M4COMMON_kOrientationTopLeft;
case M4COMMON_kOrientationTopLeft:
case M4COMMON_kOrientationTopRight:
case M4COMMON_kOrientationBottomRight:
case M4COMMON_kOrientationBottomLeft:
Params.m_outputSize.m_height = pImagePlanes->u_height;
Params.m_outputSize.m_width = pImagePlanes->u_width;
break;
case M4COMMON_kOrientationLeftTop:
case M4COMMON_kOrientationLeftBottom:
case M4COMMON_kOrientationRightTop:
case M4COMMON_kOrientationRightBottom:
Params.m_outputSize.m_height = pImagePlanes->u_width;
Params.m_outputSize.m_width = pImagePlanes->u_height;
break;
}
}
/**
Picture rendering: Cropping*/
if(pC->m_mediaRendering == M4xVSS_kCropping)
{
if((Params.m_outputSize.m_height * Params.m_inputSize.m_width)\
/Params.m_outputSize.m_width<Params.m_inputSize.m_height)
{
M4OSA_UInt32 tempHeight = Params.m_inputSize.m_height;
/*height will be cropped*/
Params.m_inputSize.m_height = (M4OSA_UInt32)((Params.m_outputSize.m_height \
* Params.m_inputSize.m_width) /Params.m_outputSize.m_width);
Params.m_inputSize.m_height = (Params.m_inputSize.m_height>>1)<<1;
if(M4OSA_FALSE == pC->m_pPto3GPPparams->isPanZoom)
{
Params.m_inputCoord.m_y = (M4OSA_Int32)((M4OSA_Int32)\
((pC->m_pDecodedPlane->u_height - Params.m_inputSize.m_height))>>1);
}
else
{
Params.m_inputCoord.m_y += (M4OSA_Int32)((M4OSA_Int32)\
((tempHeight - Params.m_inputSize.m_height))>>1);
}
}
else
{
M4OSA_UInt32 tempWidth= Params.m_inputSize.m_width;
/*width will be cropped*/
Params.m_inputSize.m_width = (M4OSA_UInt32)((Params.m_outputSize.m_width \
* Params.m_inputSize.m_height) /Params.m_outputSize.m_height);
Params.m_inputSize.m_width = (Params.m_inputSize.m_width>>1)<<1;
if(M4OSA_FALSE == pC->m_pPto3GPPparams->isPanZoom)
{
Params.m_inputCoord.m_x = (M4OSA_Int32)((M4OSA_Int32)\
((pC->m_pDecodedPlane->u_width - Params.m_inputSize.m_width))>>1);
}
else
{
Params.m_inputCoord.m_x += (M4OSA_Int32)\
(((M4OSA_Int32)(tempWidth - Params.m_inputSize.m_width))>>1);
}
}
}
/**
* Call AIR functions */
if(M4OSA_NULL == pC->m_air_context)
{
err = M4AIR_create(&pC->m_air_context, M4AIR_kYUV420P);
if(err != M4NO_ERROR)
{
free(pC->m_pDecodedPlane[0].pac_data);
free(pC->m_pDecodedPlane);
pC->m_pDecodedPlane = M4OSA_NULL;
M4OSA_TRACE1_1("M4xVSS_PictureCallbackFct:\
Error when initializing AIR: 0x%x", err);
return err;
}
}
err = M4AIR_configure(pC->m_air_context, &Params);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_PictureCallbackFct:\
Error when configuring AIR: 0x%x", err);
M4AIR_cleanUp(pC->m_air_context);
free(pC->m_pDecodedPlane[0].pac_data);
free(pC->m_pDecodedPlane);
pC->m_pDecodedPlane = M4OSA_NULL;
return err;
}
err = M4AIR_get(pC->m_air_context, pC->m_pDecodedPlane, pImagePlanes);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_PictureCallbackFct: Error when getting AIR plane: 0x%x", err);
M4AIR_cleanUp(pC->m_air_context);
free(pC->m_pDecodedPlane[0].pac_data);
free(pC->m_pDecodedPlane);
pC->m_pDecodedPlane = M4OSA_NULL;
return err;
}
pImagePlanes[0] = pImagePlanes1;
pImagePlanes[1] = pImagePlanes2;
pImagePlanes[2] = pImagePlanes3;
}
/**
* Increment the image counter */
pC->m_ImageCounter++;
/**
* Check end of sequence */
last_frame_flag = (pC->m_ImageCounter >= pC->m_NbImage);
/**
* Keep the picture duration */
*pPictureDuration = pC->m_timeDuration;
if (1 == last_frame_flag)
{
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;
}
}
if(M4OSA_NULL != pC->m_pDecodedPlane)
{
free(pC->m_pDecodedPlane[0].pac_data);
free(pC->m_pDecodedPlane);
pC->m_pDecodedPlane = M4OSA_NULL;
}
return M4PTO3GPP_WAR_LAST_PICTURE;
}
M4OSA_TRACE1_0("M4xVSS_PictureCallbackFct: Leaving ");
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4xVSS_internalStartConvertPictureTo3gp(M4OSA_Context pContext)
* @brief This function initializes Pto3GPP with the given parameters
* @note The "Pictures to 3GPP" parameters are given by the internal xVSS
* context. This context contains a pointer on the current element
* of the chained list of Pto3GPP parameters.
* @param pContext (IN) The integrator own context
*
* @return M4NO_ERROR: No error
* @return M4PTO3GPP_WAR_LAST_PICTURE: The returned image is the last one
* @return M4ERR_PARAMETER: At least one of the function parameters is null
******************************************************************************
*/
M4OSA_ERR M4xVSS_internalStartConvertPictureTo3gp(M4OSA_Context pContext)
{
/************************************************************************/
/* Definitions to generate dummy AMR file used to add AMR silence in files generated
by Pto3GPP */
#define M4VSS3GPP_AMR_AU_SILENCE_FRAME_048_SIZE 13
/* This constant is defined in M4VSS3GPP_InternalConfig.h */
extern const M4OSA_UInt8\
M4VSS3GPP_AMR_AU_SILENCE_FRAME_048[M4VSS3GPP_AMR_AU_SILENCE_FRAME_048_SIZE];
/* AMR silent frame used to compute dummy AMR silence file */
#define M4VSS3GPP_AMR_HEADER_SIZE 6
const M4OSA_UInt8 M4VSS3GPP_AMR_HEADER[M4VSS3GPP_AMR_AU_SILENCE_FRAME_048_SIZE] =
{ 0x23, 0x21, 0x41, 0x4d, 0x52, 0x0a };
/************************************************************************/
M4xVSS_Context* xVSS_context = (M4xVSS_Context*)pContext;
M4OSA_ERR err;
M4PTO3GPP_Context pM4PTO3GPP_Ctxt = M4OSA_NULL;
M4PTO3GPP_Params Params;
M4xVSS_PictureCallbackCtxt* pCallBackCtxt;
M4OSA_Bool cmpResult=M4OSA_FALSE;
M4OSA_Context pDummyAMRFile;
M4OSA_Char out_amr[M4XVSS_MAX_PATH_LEN];
/*UTF conversion support*/
M4OSA_Char* pDecodedPath = M4OSA_NULL;
M4OSA_UInt32 i;
/**
* Create a M4PTO3GPP instance */
err = M4PTO3GPP_Init( &pM4PTO3GPP_Ctxt, xVSS_context->pFileReadPtr,
xVSS_context->pFileWritePtr);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalStartConvertPictureTo3gp returned %ld\n",err);
return err;
}
pCallBackCtxt = (M4xVSS_PictureCallbackCtxt*)M4OSA_32bitAlignedMalloc(sizeof(M4xVSS_PictureCallbackCtxt),
M4VS,(M4OSA_Char *) "Pto3gpp callback struct");
if(pCallBackCtxt == M4OSA_NULL)
{
M4OSA_TRACE1_0("Allocation error in M4xVSS_internalStartConvertPictureTo3gp");
return M4ERR_ALLOC;
}
Params.OutputVideoFrameSize = xVSS_context->pSettings->xVSS.outputVideoSize;
Params.OutputVideoFormat = xVSS_context->pSettings->xVSS.outputVideoFormat;
Params.videoProfile = xVSS_context->pSettings->xVSS.outputVideoProfile;
Params.videoLevel = xVSS_context->pSettings->xVSS.outputVideoLevel;
/**
* Generate "dummy" amr file containing silence in temporary folder */
M4OSA_chrNCopy(out_amr, xVSS_context->pTempPath, M4XVSS_MAX_PATH_LEN - 1);
strncat((char *)out_amr, (const char *)"dummy.amr\0", 10);
/**
* UTF conversion: convert the temporary path into the customer format*/
pDecodedPath = out_amr;
if(xVSS_context->UTFConversionContext.pConvFromUTF8Fct != M4OSA_NULL
&& xVSS_context->UTFConversionContext.pTempOutConversionBuffer != M4OSA_NULL)
{
M4OSA_UInt32 length = 0;
err = M4xVSS_internalConvertFromUTF8(xVSS_context, (M4OSA_Void*) out_amr,
(M4OSA_Void*) xVSS_context->UTFConversionContext.pTempOutConversionBuffer, &length);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalStartConvertPictureTo3gp:\
M4xVSS_internalConvertFromUTF8 returns err: 0x%x",err);
return err;
}
pDecodedPath = xVSS_context->UTFConversionContext.pTempOutConversionBuffer;
}
/**
* End of the conversion, now use the converted path*/
err = xVSS_context->pFileWritePtr->openWrite(&pDummyAMRFile, pDecodedPath, M4OSA_kFileWrite);
/*Commented because of the use of the UTF conversion see above*/
/* err = xVSS_context->pFileWritePtr->openWrite(&pDummyAMRFile, out_amr, M4OSA_kFileWrite);
*/
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_2("M4xVSS_internalConvertPictureTo3gp: Can't open output dummy amr file %s,\
error: 0x%x\n",out_amr, err);
return err;
}
err = xVSS_context->pFileWritePtr->writeData(pDummyAMRFile,
(M4OSA_Int8*)M4VSS3GPP_AMR_HEADER, M4VSS3GPP_AMR_HEADER_SIZE);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_2("M4xVSS_internalConvertPictureTo3gp: Can't write output dummy amr file %s,\
error: 0x%x\n",out_amr, err);
return err;
}
err = xVSS_context->pFileWritePtr->writeData(pDummyAMRFile,
(M4OSA_Int8*)M4VSS3GPP_AMR_AU_SILENCE_FRAME_048, M4VSS3GPP_AMR_AU_SILENCE_FRAME_048_SIZE);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_2("M4xVSS_internalConvertPictureTo3gp: \
Can't write output dummy amr file %s, error: 0x%x\n",out_amr, err);
return err;
}
err = xVSS_context->pFileWritePtr->closeWrite(pDummyAMRFile);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_2("M4xVSS_internalConvertPictureTo3gp: \
Can't close output dummy amr file %s, error: 0x%x\n",out_amr, err);
return err;
}
/**
* Fill parameters for Pto3GPP with the parameters contained in the current element of the
* Pto3GPP parameters chained list and with default parameters */
/*+ New Encoder bitrates */
if(xVSS_context->pSettings->xVSS.outputVideoBitrate == 0) {
Params.OutputVideoBitrate = M4VIDEOEDITING_kVARIABLE_KBPS;
}
else {
Params.OutputVideoBitrate = xVSS_context->pSettings->xVSS.outputVideoBitrate;
}
M4OSA_TRACE1_1("M4xVSS_internalStartConvertPicTo3GP: video bitrate = %d",
Params.OutputVideoBitrate);
/*- New Encoder bitrates */
Params.OutputFileMaxSize = M4PTO3GPP_kUNLIMITED;
Params.pPictureCallbackFct = M4xVSS_PictureCallbackFct;
Params.pPictureCallbackCtxt = pCallBackCtxt;
/*FB: change to use the converted path (UTF conversion) see the conversion above*/
/*Fix :- Adding Audio Track in Image as input :AudioTarckFile Setting to NULL */
Params.pInputAudioTrackFile = M4OSA_NULL;//(M4OSA_Void*)pDecodedPath;//out_amr;
Params.AudioPaddingMode = M4PTO3GPP_kAudioPaddingMode_Loop;
Params.AudioFileFormat = M4VIDEOEDITING_kFileType_AMR;
Params.pOutput3gppFile = xVSS_context->pPTo3GPPcurrentParams->pFileOut;
Params.pTemporaryFile = xVSS_context->pPTo3GPPcurrentParams->pFileTemp;
/*+PR No: blrnxpsw#223*/
/*Increasing frequency of Frame, calculating Nos of Frame = duration /FPS */
/*Other changes made is @ M4xVSS_API.c @ line 3841 in M4xVSS_SendCommand*/
/*If case check for PanZoom removed */
Params.NbVideoFrames = (M4OSA_UInt32)
(xVSS_context->pPTo3GPPcurrentParams->duration \
/ xVSS_context->pPTo3GPPcurrentParams->framerate); /* */
pCallBackCtxt->m_timeDuration = xVSS_context->pPTo3GPPcurrentParams->framerate;
/*-PR No: blrnxpsw#223*/
pCallBackCtxt->m_ImageCounter = 0;
pCallBackCtxt->m_FileIn = xVSS_context->pPTo3GPPcurrentParams->pFileIn;
pCallBackCtxt->m_NbImage = Params.NbVideoFrames;
pCallBackCtxt->m_pFileReadPtr = xVSS_context->pFileReadPtr;
pCallBackCtxt->m_pDecodedPlane = M4OSA_NULL;
pCallBackCtxt->m_pPto3GPPparams = xVSS_context->pPTo3GPPcurrentParams;
pCallBackCtxt->m_air_context = M4OSA_NULL;
pCallBackCtxt->m_mediaRendering = xVSS_context->pPTo3GPPcurrentParams->MediaRendering;
/**
* Set the input and output files */
err = M4PTO3GPP_Open(pM4PTO3GPP_Ctxt, &Params);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4PTO3GPP_Open returned: 0x%x\n",err);
if(pCallBackCtxt != M4OSA_NULL)
{
free(pCallBackCtxt);
pCallBackCtxt = M4OSA_NULL;
}
M4PTO3GPP_CleanUp(pM4PTO3GPP_Ctxt);
return err;
}
/**
* Save context to be able to call Pto3GPP step function in M4xVSS_step function */
xVSS_context->pM4PTO3GPP_Ctxt = pM4PTO3GPP_Ctxt;
xVSS_context->pCallBackCtxt = pCallBackCtxt;
return M4NO_ERROR;
}
/**
******************************************************************************
* M4OSA_ERR M4xVSS_internalStopConvertPictureTo3gp(M4OSA_Context pContext)
* @brief This function cleans up Pto3GPP
* @note
* @param pContext (IN) The integrator own context
*
* @return M4NO_ERROR: No error
* @return M4ERR_PARAMETER: At least one of the function parameters is null
******************************************************************************
*/
M4OSA_ERR M4xVSS_internalStopConvertPictureTo3gp(M4OSA_Context pContext)
{
M4xVSS_Context* xVSS_context = (M4xVSS_Context*)pContext;
M4OSA_ERR err;
M4OSA_Char out_amr[M4XVSS_MAX_PATH_LEN];
/*UTF conversion support*/
M4OSA_Char* pDecodedPath = M4OSA_NULL;
/**
* Free the PTO3GPP callback context */
if(M4OSA_NULL != xVSS_context->pCallBackCtxt)
{
free(xVSS_context->pCallBackCtxt);
xVSS_context->pCallBackCtxt = M4OSA_NULL;
}
/**
* Finalize the output file */
err = M4PTO3GPP_Close(xVSS_context->pM4PTO3GPP_Ctxt);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4PTO3GPP_Close returned 0x%x\n",err);
M4PTO3GPP_CleanUp(xVSS_context->pM4PTO3GPP_Ctxt);
return err;
}
/**
* Free this M4PTO3GPP instance */
err = M4PTO3GPP_CleanUp(xVSS_context->pM4PTO3GPP_Ctxt);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4PTO3GPP_CleanUp returned 0x%x\n",err);
return err;
}
/**
* Remove dummy.amr file */
M4OSA_chrNCopy(out_amr, xVSS_context->pTempPath, M4XVSS_MAX_PATH_LEN - 1);
strncat((char *)out_amr, (const char *)"dummy.amr\0", 10);
/**
* UTF conversion: convert the temporary path into the customer format*/
pDecodedPath = out_amr;
if(xVSS_context->UTFConversionContext.pConvFromUTF8Fct != M4OSA_NULL
&& xVSS_context->UTFConversionContext.pTempOutConversionBuffer != M4OSA_NULL)
{
M4OSA_UInt32 length = 0;
err = M4xVSS_internalConvertFromUTF8(xVSS_context, (M4OSA_Void*) out_amr,
(M4OSA_Void*) xVSS_context->UTFConversionContext.pTempOutConversionBuffer, &length);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalStopConvertPictureTo3gp:\
M4xVSS_internalConvertFromUTF8 returns err: 0x%x",err);
return err;
}
pDecodedPath = xVSS_context->UTFConversionContext.pTempOutConversionBuffer;
}
/**
* End of the conversion, now use the decoded path*/
remove((const char *)pDecodedPath);
/*Commented because of the use of the UTF conversion*/
/* remove(out_amr);
*/
xVSS_context->pM4PTO3GPP_Ctxt = M4OSA_NULL;
xVSS_context->pCallBackCtxt = M4OSA_NULL;
return M4NO_ERROR;
}
/**
******************************************************************************
* prototype M4OSA_ERR M4xVSS_internalConvertRGBtoYUV(M4xVSS_FramingStruct* framingCtx)
* @brief This function converts an RGB565 plane to YUV420 planar
* @note It is used only for framing effect
* It allocates output YUV planes
* @param framingCtx (IN) The framing struct containing input RGB565 plane
*
* @return M4NO_ERROR: No error
* @return M4ERR_PARAMETER: At least one of the function parameters is null
* @return M4ERR_ALLOC: Allocation error (no more memory)
******************************************************************************
*/
M4OSA_ERR M4xVSS_internalConvertRGBtoYUV(M4xVSS_FramingStruct* framingCtx)
{
M4OSA_ERR err;
/**
* Allocate output YUV planes */
framingCtx->FramingYuv = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(3*sizeof(M4VIFI_ImagePlane),
M4VS, (M4OSA_Char *)"M4xVSS_internalConvertRGBtoYUV: Output plane YUV");
if(framingCtx->FramingYuv == M4OSA_NULL)
{
M4OSA_TRACE1_0("Allocation error in M4xVSS_internalConvertRGBtoYUV");
return M4ERR_ALLOC;
}
framingCtx->FramingYuv[0].u_width = framingCtx->FramingRgb->u_width;
framingCtx->FramingYuv[0].u_height = framingCtx->FramingRgb->u_height;
framingCtx->FramingYuv[0].u_topleft = 0;
framingCtx->FramingYuv[0].u_stride = framingCtx->FramingRgb->u_width;
framingCtx->FramingYuv[0].pac_data =
(M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc((framingCtx->FramingYuv[0].u_width\
*framingCtx->FramingYuv[0].u_height*3)>>1, M4VS, (M4OSA_Char *)\
"Alloc for the Convertion output YUV");;
if(framingCtx->FramingYuv[0].pac_data == M4OSA_NULL)
{
M4OSA_TRACE1_0("Allocation error in M4xVSS_internalConvertRGBtoYUV");
return M4ERR_ALLOC;
}
framingCtx->FramingYuv[1].u_width = (framingCtx->FramingRgb->u_width)>>1;
framingCtx->FramingYuv[1].u_height = (framingCtx->FramingRgb->u_height)>>1;
framingCtx->FramingYuv[1].u_topleft = 0;
framingCtx->FramingYuv[1].u_stride = (framingCtx->FramingRgb->u_width)>>1;
framingCtx->FramingYuv[1].pac_data = framingCtx->FramingYuv[0].pac_data \
+ framingCtx->FramingYuv[0].u_width * framingCtx->FramingYuv[0].u_height;
framingCtx->FramingYuv[2].u_width = (framingCtx->FramingRgb->u_width)>>1;
framingCtx->FramingYuv[2].u_height = (framingCtx->FramingRgb->u_height)>>1;
framingCtx->FramingYuv[2].u_topleft = 0;
framingCtx->FramingYuv[2].u_stride = (framingCtx->FramingRgb->u_width)>>1;
framingCtx->FramingYuv[2].pac_data = framingCtx->FramingYuv[1].pac_data \
+ framingCtx->FramingYuv[1].u_width * framingCtx->FramingYuv[1].u_height;
/**
* Convert input RGB 565 to YUV 420 to be able to merge it with output video in framing
effect */
err = M4VIFI_xVSS_RGB565toYUV420(M4OSA_NULL, framingCtx->FramingRgb, framingCtx->FramingYuv);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalConvertRGBtoYUV:\
error when converting from RGB to YUV: 0x%x\n", err);
}
framingCtx->duration = 0;
framingCtx->previousClipTime = -1;
framingCtx->previewOffsetClipTime = -1;
/**
* Only one element in the chained list (no animated image with RGB buffer...) */
framingCtx->pCurrent = framingCtx;
framingCtx->pNext = framingCtx;
return M4NO_ERROR;
}
M4OSA_ERR M4xVSS_internalSetPlaneTransparent(M4OSA_UInt8* planeIn, M4OSA_UInt32 size)
{
M4OSA_UInt32 i;
M4OSA_UInt8* plane = planeIn;
M4OSA_UInt8 transparent1 = (M4OSA_UInt8)((TRANSPARENT_COLOR & 0xFF00)>>8);
M4OSA_UInt8 transparent2 = (M4OSA_UInt8)TRANSPARENT_COLOR;
for(i=0; i<(size>>1); i++)
{
*plane++ = transparent1;
*plane++ = transparent2;
}
return M4NO_ERROR;
}
/**
******************************************************************************
* prototype M4OSA_ERR M4xVSS_internalConvertARBG888toYUV420_FrammingEffect(M4OSA_Context pContext,
* M4VSS3GPP_EffectSettings* pEffect,
* M4xVSS_FramingStruct* framingCtx,
M4VIDEOEDITING_VideoFrameSize OutputVideoResolution)
*
* @brief This function converts ARGB8888 input file to YUV420 whenused for framming effect
* @note The input ARGB8888 file path is contained in the pEffect structure
* If the ARGB8888 must be resized to fit output video size, this function
* will do it.
* @param pContext (IN) The integrator own context
* @param pEffect (IN) The effect structure containing all informations on
* the file to decode, resizing ...
* @param framingCtx (IN/OUT) Structure in which the output RGB will be stored
*
* @return M4NO_ERROR: No error
* @return M4ERR_PARAMETER: At least one of the function parameters is null
* @return M4ERR_ALLOC: Allocation error (no more memory)
* @return M4ERR_FILE_NOT_FOUND: File not found.
******************************************************************************
*/
M4OSA_ERR M4xVSS_internalConvertARGB888toYUV420_FrammingEffect(M4OSA_Context pContext,
M4VSS3GPP_EffectSettings* pEffect,
M4xVSS_FramingStruct* framingCtx,
M4VIDEOEDITING_VideoFrameSize\
OutputVideoResolution)
{
M4OSA_ERR err = M4NO_ERROR;
M4OSA_Context pARGBIn;
M4OSA_UInt32 file_size;
M4xVSS_Context* xVSS_context = (M4xVSS_Context*)pContext;
M4OSA_UInt32 width, height, width_out, height_out;
M4OSA_Void* pFile = pEffect->xVSS.pFramingFilePath;
M4OSA_UInt8 transparent1 = (M4OSA_UInt8)((TRANSPARENT_COLOR & 0xFF00)>>8);
M4OSA_UInt8 transparent2 = (M4OSA_UInt8)TRANSPARENT_COLOR;
/*UTF conversion support*/
M4OSA_Char* pDecodedPath = M4OSA_NULL;
M4OSA_UInt32 i = 0,j = 0;
M4VIFI_ImagePlane rgbPlane;
M4OSA_UInt32 frameSize_argb=(framingCtx->width * framingCtx->height * 4);
M4OSA_UInt32 frameSize;
M4OSA_UInt32 tempAlphaPercent = 0;
M4VIFI_UInt8* TempPacData = M4OSA_NULL;
M4OSA_UInt16 *ptr = M4OSA_NULL;
M4OSA_UInt32 z = 0;
M4OSA_TRACE3_0("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect: Entering ");
M4OSA_TRACE1_2("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect width and height %d %d ",
framingCtx->width,framingCtx->height);
M4OSA_UInt8 *pTmpData = (M4OSA_UInt8*) M4OSA_32bitAlignedMalloc(frameSize_argb, M4VS, (M4OSA_Char*)\
"Image argb data");
if(pTmpData == M4OSA_NULL) {
M4OSA_TRACE1_0("Failed to allocate memory for Image clip");
return M4ERR_ALLOC;
}
/**
* UTF conversion: convert the file path into the customer format*/
pDecodedPath = pFile;
if(xVSS_context->UTFConversionContext.pConvFromUTF8Fct != M4OSA_NULL
&& xVSS_context->UTFConversionContext.pTempOutConversionBuffer != M4OSA_NULL)
{
M4OSA_UInt32 length = 0;
err = M4xVSS_internalConvertFromUTF8(xVSS_context, (M4OSA_Void*) pFile,
(M4OSA_Void*) xVSS_context->UTFConversionContext.pTempOutConversionBuffer, &length);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalDecodePNG:\
M4xVSS_internalConvertFromUTF8 returns err: 0x%x",err);
free(pTmpData);
pTmpData = M4OSA_NULL;
return err;
}
pDecodedPath = xVSS_context->UTFConversionContext.pTempOutConversionBuffer;
}
/**
* End of the conversion, now use the decoded path*/
/* Open input ARGB8888 file and store it into memory */
err = xVSS_context->pFileReadPtr->openRead(&pARGBIn, pDecodedPath, M4OSA_kFileRead);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_2("Can't open input ARGB8888 file %s, error: 0x%x\n",pFile, err);
free(pTmpData);
pTmpData = M4OSA_NULL;
return err;
}
err = xVSS_context->pFileReadPtr->readData(pARGBIn,(M4OSA_MemAddr8)pTmpData, &frameSize_argb);
if(err != M4NO_ERROR)
{
xVSS_context->pFileReadPtr->closeRead(pARGBIn);
free(pTmpData);
pTmpData = M4OSA_NULL;
return err;
}
err = xVSS_context->pFileReadPtr->closeRead(pARGBIn);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_2("Can't close input png file %s, error: 0x%x\n",pFile, err);
free(pTmpData);
pTmpData = M4OSA_NULL;
return err;
}
rgbPlane.u_height = framingCtx->height;
rgbPlane.u_width = framingCtx->width;
rgbPlane.u_stride = rgbPlane.u_width*3;
rgbPlane.u_topleft = 0;
frameSize = (rgbPlane.u_width * rgbPlane.u_height * 3); //Size of RGB888 data
rgbPlane.pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(((frameSize)+ (2 * framingCtx->width)),
M4VS, (M4OSA_Char*)"Image clip RGB888 data");
if(rgbPlane.pac_data == M4OSA_NULL)
{
M4OSA_TRACE1_0("Failed to allocate memory for Image clip");
free(pTmpData);
return M4ERR_ALLOC;
}
M4OSA_TRACE1_0("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect:\
Remove the alpha channel ");
/* premultiplied alpha % on RGB */
for (i=0, j = 0; i < frameSize_argb; i += 4) {
/* this is alpha value */
if ((i % 4) == 0)
{
tempAlphaPercent = pTmpData[i];
}
/* R */
rgbPlane.pac_data[j] = pTmpData[i+1];
j++;
/* G */
if (tempAlphaPercent > 0) {
rgbPlane.pac_data[j] = pTmpData[i+2];
j++;
} else {/* In case of alpha value 0, make GREEN to 255 */
rgbPlane.pac_data[j] = 255; //pTmpData[i+2];
j++;
}
/* B */
rgbPlane.pac_data[j] = pTmpData[i+3];
j++;
}
free(pTmpData);
pTmpData = M4OSA_NULL;
/* convert RGB888 to RGB565 */
/* allocate temp RGB 565 buffer */
TempPacData = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(frameSize +
(4 * (framingCtx->width + framingCtx->height + 1)),
M4VS, (M4OSA_Char*)"Image clip RGB565 data");
if (TempPacData == M4OSA_NULL) {
M4OSA_TRACE1_0("Failed to allocate memory for Image clip RGB565 data");
free(rgbPlane.pac_data);
return M4ERR_ALLOC;
}
ptr = (M4OSA_UInt16 *)TempPacData;
z = 0;
for (i = 0; i < j ; i += 3)
{
ptr[z++] = PACK_RGB565(0, rgbPlane.pac_data[i],
rgbPlane.pac_data[i+1],
rgbPlane.pac_data[i+2]);
}
/* free the RBG888 and assign RGB565 */
free(rgbPlane.pac_data);
rgbPlane.pac_data = TempPacData;
/**
* Check if output sizes are odd */
if(rgbPlane.u_height % 2 != 0)
{
M4VIFI_UInt8* output_pac_data = rgbPlane.pac_data;
M4OSA_UInt32 i;
M4OSA_TRACE1_0("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect:\
output height is odd ");
output_pac_data +=rgbPlane.u_width * rgbPlane.u_height*2;
for(i=0;i<rgbPlane.u_width;i++)
{
*output_pac_data++ = transparent1;
*output_pac_data++ = transparent2;
}
/**
* We just add a white line to the PNG that will be transparent */
rgbPlane.u_height++;
}
if(rgbPlane.u_width % 2 != 0)
{
/**
* We add a new column of white (=transparent), but we need to parse all RGB lines ... */
M4OSA_UInt32 i;
M4VIFI_UInt8* newRGBpac_data;
M4VIFI_UInt8* output_pac_data, *input_pac_data;
rgbPlane.u_width++;
M4OSA_TRACE1_0("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect: \
output width is odd ");
/**
* We need to allocate a new RGB output buffer in which all decoded data
+ white line will be copied */
newRGBpac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(rgbPlane.u_height*rgbPlane.u_width*2\
*sizeof(M4VIFI_UInt8), M4VS, (M4OSA_Char *)"New Framing GIF Output pac_data RGB");
if(newRGBpac_data == M4OSA_NULL)
{
M4OSA_TRACE1_0("Allocation error in \
M4xVSS_internalConvertARGB888toYUV420_FrammingEffect");
free(rgbPlane.pac_data);
return M4ERR_ALLOC;
}
output_pac_data= newRGBpac_data;
input_pac_data = rgbPlane.pac_data;
for(i=0;i<rgbPlane.u_height;i++)
{
memcpy((void *)output_pac_data, (void *)input_pac_data,
(rgbPlane.u_width-1)*2);
output_pac_data += ((rgbPlane.u_width-1)*2);
/* Put the pixel to transparency color */
*output_pac_data++ = transparent1;
*output_pac_data++ = transparent2;
input_pac_data += ((rgbPlane.u_width-1)*2);
}
free(rgbPlane.pac_data);
rgbPlane.pac_data = newRGBpac_data;
}
/* reset stride */
rgbPlane.u_stride = rgbPlane.u_width*2;
/**
* Initialize chained list parameters */
framingCtx->duration = 0;
framingCtx->previousClipTime = -1;
framingCtx->previewOffsetClipTime = -1;
/**
* Only one element in the chained list (no animated image ...) */
framingCtx->pCurrent = framingCtx;
framingCtx->pNext = framingCtx;
/**
* Get output width/height */
switch(OutputVideoResolution)
//switch(xVSS_context->pSettings->xVSS.outputVideoSize)
{
case M4VIDEOEDITING_kSQCIF:
width_out = 128;
height_out = 96;
break;
case M4VIDEOEDITING_kQQVGA:
width_out = 160;
height_out = 120;
break;
case M4VIDEOEDITING_kQCIF:
width_out = 176;
height_out = 144;
break;
case M4VIDEOEDITING_kQVGA:
width_out = 320;
height_out = 240;
break;
case M4VIDEOEDITING_kCIF:
width_out = 352;
height_out = 288;
break;
case M4VIDEOEDITING_kVGA:
width_out = 640;
height_out = 480;
break;
case M4VIDEOEDITING_kWVGA:
width_out = 800;
height_out = 480;
break;
case M4VIDEOEDITING_kNTSC:
width_out = 720;
height_out = 480;
break;
case M4VIDEOEDITING_k640_360:
width_out = 640;
height_out = 360;
break;
case M4VIDEOEDITING_k854_480:
// StageFright encoders require %16 resolution
width_out = M4ENCODER_854_480_Width;
height_out = 480;
break;
case M4VIDEOEDITING_k1280_720:
width_out = 1280;
height_out = 720;
break;
case M4VIDEOEDITING_k1080_720:
// StageFright encoders require %16 resolution
width_out = M4ENCODER_1080_720_Width;
height_out = 720;
break;
case M4VIDEOEDITING_k960_720:
width_out = 960;
height_out = 720;
break;
case M4VIDEOEDITING_k1920_1080:
width_out = 1920;
height_out = M4ENCODER_1920_1080_Height;
break;
/**
* If output video size is not given, we take QCIF size,
* should not happen, because already done in M4xVSS_sendCommand */
default:
width_out = 176;
height_out = 144;
break;
}
/**
* Allocate output planes structures */
framingCtx->FramingRgb = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(sizeof(M4VIFI_ImagePlane), M4VS,
(M4OSA_Char *)"Framing Output plane RGB");
if(framingCtx->FramingRgb == M4OSA_NULL)
{
M4OSA_TRACE1_0("Allocation error in M4xVSS_internalConvertARGB888toYUV420_FrammingEffect");
return M4ERR_ALLOC;
}
/**
* Resize RGB if needed */
if((pEffect->xVSS.bResize) &&
(rgbPlane.u_width != width_out || rgbPlane.u_height != height_out))
{
width = width_out;
height = height_out;
M4OSA_TRACE1_2("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect: \
New Width and height %d %d ",width,height);
framingCtx->FramingRgb->u_height = height_out;
framingCtx->FramingRgb->u_width = width_out;
framingCtx->FramingRgb->u_stride = framingCtx->FramingRgb->u_width*2;
framingCtx->FramingRgb->u_topleft = 0;
framingCtx->FramingRgb->pac_data =
(M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(framingCtx->FramingRgb->u_height*framingCtx->\
FramingRgb->u_width*2*sizeof(M4VIFI_UInt8), M4VS,
(M4OSA_Char *)"Framing Output pac_data RGB");
if(framingCtx->FramingRgb->pac_data == M4OSA_NULL)
{
M4OSA_TRACE1_0("Allocation error in \
M4xVSS_internalConvertARGB888toYUV420_FrammingEffect");
free(framingCtx->FramingRgb);
free(rgbPlane.pac_data);
return M4ERR_ALLOC;
}
M4OSA_TRACE1_0("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect: Resizing Needed ");
M4OSA_TRACE1_2("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect:\
rgbPlane.u_height & rgbPlane.u_width %d %d",rgbPlane.u_height,rgbPlane.u_width);
//err = M4VIFI_ResizeBilinearRGB888toRGB888(M4OSA_NULL, &rgbPlane,framingCtx->FramingRgb);
err = M4VIFI_ResizeBilinearRGB565toRGB565(M4OSA_NULL, &rgbPlane,framingCtx->FramingRgb);
if(err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect :\
when resizing RGB plane: 0x%x\n", err);
return err;
}
if(rgbPlane.pac_data != M4OSA_NULL)
{
free(rgbPlane.pac_data);
rgbPlane.pac_data = M4OSA_NULL;
}
}
else
{
M4OSA_TRACE1_0("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect:\
Resizing Not Needed ");
width = rgbPlane.u_width;
height = rgbPlane.u_height;
framingCtx->FramingRgb->u_height = height;
framingCtx->FramingRgb->u_width = width;
framingCtx->FramingRgb->u_stride = framingCtx->FramingRgb->u_width*2;
framingCtx->FramingRgb->u_topleft = 0;
framingCtx->FramingRgb->pac_data = rgbPlane.pac_data;
}
if(pEffect->xVSS.bResize)
{
/**
* Force topleft to 0 for pure framing effect */
framingCtx->topleft_x = 0;
framingCtx->topleft_y = 0;
}
/**
* Convert RGB output to YUV 420 to be able to merge it with output video in framing
effect */
framingCtx->FramingYuv = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(3*sizeof(M4VIFI_ImagePlane), M4VS,
(M4OSA_Char *)"Framing Output plane YUV");
if(framingCtx->FramingYuv == M4OSA_NULL)
{
M4OSA_TRACE1_0("Allocation error in M4xVSS_internalConvertARGB888toYUV420_FrammingEffect");
free(framingCtx->FramingRgb->pac_data);
return M4ERR_ALLOC;
}
// Alloc for Y, U and V planes
framingCtx->FramingYuv[0].u_width = ((width+1)>>1)<<1;
framingCtx->FramingYuv[0].u_height = ((height+1)>>1)<<1;
framingCtx->FramingYuv[0].u_topleft = 0;
framingCtx->FramingYuv[0].u_stride = ((width+1)>>1)<<1;
framingCtx->FramingYuv[0].pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc
((framingCtx->FramingYuv[0].u_width*framingCtx->FramingYuv[0].u_height), M4VS,
(M4OSA_Char *)"Alloc for the output Y");
if(framingCtx->FramingYuv[0].pac_data == M4OSA_NULL)
{
M4OSA_TRACE1_0("Allocation error in M4xVSS_internalConvertARGB888toYUV420_FrammingEffect");
free(framingCtx->FramingYuv);
free(framingCtx->FramingRgb->pac_data);
return M4ERR_ALLOC;
}
framingCtx->FramingYuv[1].u_width = (((width+1)>>1)<<1)>>1;
framingCtx->FramingYuv[1].u_height = (((height+1)>>1)<<1)>>1;
framingCtx->FramingYuv[1].u_topleft = 0;
framingCtx->FramingYuv[1].u_stride = (((width+1)>>1)<<1)>>1;
framingCtx->FramingYuv[1].pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(
framingCtx->FramingYuv[1].u_width * framingCtx->FramingYuv[1].u_height, M4VS,
(M4OSA_Char *)"Alloc for the output U");
if (framingCtx->FramingYuv[1].pac_data == M4OSA_NULL) {
free(framingCtx->FramingYuv[0].pac_data);
free(framingCtx->FramingYuv);
free(framingCtx->FramingRgb->pac_data);
return M4ERR_ALLOC;
}
framingCtx->FramingYuv[2].u_width = (((width+1)>>1)<<1)>>1;
framingCtx->FramingYuv[2].u_height = (((height+1)>>1)<<1)>>1;
framingCtx->FramingYuv[2].u_topleft = 0;
framingCtx->FramingYuv[2].u_stride = (((width+1)>>1)<<1)>>1;
framingCtx->FramingYuv[2].pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(
framingCtx->FramingYuv[2].u_width * framingCtx->FramingYuv[0].u_height, M4VS,
(M4OSA_Char *)"Alloc for the output V");
if (framingCtx->FramingYuv[2].pac_data == M4OSA_NULL) {
free(framingCtx->FramingYuv[1].pac_data);
free(framingCtx->FramingYuv[0].pac_data);
free(framingCtx->FramingYuv);
free(framingCtx->FramingRgb->pac_data);
return M4ERR_ALLOC;
}
M4OSA_TRACE3_0("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect:\
convert RGB to YUV ");
//err = M4VIFI_RGB888toYUV420(M4OSA_NULL, framingCtx->FramingRgb, framingCtx->FramingYuv);
err = M4VIFI_RGB565toYUV420(M4OSA_NULL, framingCtx->FramingRgb, framingCtx->FramingYuv);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("SPS png: error when converting from RGB to YUV: 0x%x\n", err);
}
M4OSA_TRACE3_0("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect: Leaving ");
return err;
}
/**
******************************************************************************
* prototype M4OSA_ERR M4xVSS_internalGenerateEditedFile(M4OSA_Context pContext)
*
* @brief This function prepares VSS for editing
* @note It also set special xVSS effect as external effects for the VSS
* @param pContext (IN) The integrator own context
*
* @return M4NO_ERROR: No error
* @return M4ERR_PARAMETER: At least one of the function parameters is null
* @return M4ERR_ALLOC: Allocation error (no more memory)
******************************************************************************
*/
M4OSA_ERR M4xVSS_internalGenerateEditedFile(M4OSA_Context pContext)
{
M4xVSS_Context* xVSS_context = (M4xVSS_Context*)pContext;
M4VSS3GPP_EditContext pVssCtxt;
M4OSA_UInt32 i,j;
M4OSA_ERR err;
/**
* Create a VSS 3GPP edition instance */
err = M4VSS3GPP_editInit( &pVssCtxt, xVSS_context->pFileReadPtr, xVSS_context->pFileWritePtr);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalGenerateEditedFile: M4VSS3GPP_editInit returned 0x%x\n",
err);
M4VSS3GPP_editCleanUp(pVssCtxt);
/**
* Set the VSS context to NULL */
xVSS_context->pCurrentEditContext = M4OSA_NULL;
return err;
}
M4VSS3GPP_InternalEditContext* pVSSContext =
(M4VSS3GPP_InternalEditContext*)pVssCtxt;
pVSSContext->xVSS.outputVideoFormat =
xVSS_context->pSettings->xVSS.outputVideoFormat;
pVSSContext->xVSS.outputVideoSize =
xVSS_context->pSettings->xVSS.outputVideoSize ;
pVSSContext->xVSS.outputAudioFormat =
xVSS_context->pSettings->xVSS.outputAudioFormat;
pVSSContext->xVSS.outputAudioSamplFreq =
xVSS_context->pSettings->xVSS.outputAudioSamplFreq;
pVSSContext->xVSS.outputVideoBitrate =
xVSS_context->pSettings->xVSS.outputVideoBitrate ;
pVSSContext->xVSS.outputAudioBitrate =
xVSS_context->pSettings->xVSS.outputAudioBitrate ;
pVSSContext->xVSS.bAudioMono =
xVSS_context->pSettings->xVSS.bAudioMono;
pVSSContext->xVSS.outputVideoProfile =
xVSS_context->pSettings->xVSS.outputVideoProfile;
pVSSContext->xVSS.outputVideoLevel =
xVSS_context->pSettings->xVSS.outputVideoLevel;
/* In case of MMS use case, we fill directly into the VSS context the targeted bitrate */
if(xVSS_context->targetedBitrate != 0)
{
M4VSS3GPP_InternalEditContext* pVSSContext = (M4VSS3GPP_InternalEditContext*)pVssCtxt;
pVSSContext->bIsMMS = M4OSA_TRUE;
pVSSContext->uiMMSVideoBitrate = xVSS_context->targetedBitrate;
pVSSContext->MMSvideoFramerate = xVSS_context->pSettings->videoFrameRate;
}
/*Warning: since the adding of the UTF conversion, pSettings has been changed in the next
part in pCurrentEditSettings (there is a specific current editing structure for the saving,
as for the preview)*/
/**
* Set the external video effect functions, for saving mode (to be moved to
M4xVSS_saveStart() ?)*/
for (i=0; i<xVSS_context->pCurrentEditSettings->uiClipNumber; i++)
{
for (j=0; j<xVSS_context->pCurrentEditSettings->nbEffects; j++)
{
if (M4xVSS_kVideoEffectType_BlackAndWhite ==
xVSS_context->pCurrentEditSettings->Effects[j].VideoEffectType)
{
xVSS_context->pCurrentEditSettings->Effects[j].ExtVideoEffectFct =
M4VSS3GPP_externalVideoEffectColor;
//xVSS_context->pSettings->Effects[j].pExtVideoEffectFctCtxt =
// (M4OSA_Void*)M4xVSS_kVideoEffectType_BlackAndWhite;
/*commented FB*/
/**
* We do not need to set the color context, it is already set
during sendCommand function */
}
if (M4xVSS_kVideoEffectType_Pink ==
xVSS_context->pCurrentEditSettings->Effects[j].VideoEffectType)
{
xVSS_context->pCurrentEditSettings->Effects[j].ExtVideoEffectFct =
M4VSS3GPP_externalVideoEffectColor;
//xVSS_context->pSettings->Effects[j].pExtVideoEffectFctCtxt =
// (M4OSA_Void*)M4xVSS_kVideoEffectType_Pink; /**< we don't
// use any function context */
/*commented FB*/
/**
* We do not need to set the color context,
it is already set during sendCommand function */
}
if (M4xVSS_kVideoEffectType_Green ==
xVSS_context->pCurrentEditSettings->Effects[j].VideoEffectType)
{
xVSS_context->pCurrentEditSettings->Effects[j].ExtVideoEffectFct =
M4VSS3GPP_externalVideoEffectColor;
//xVSS_context->pSettings->Effects[j].pExtVideoEffectFctCtxt =
// (M4OSA_Void*)M4xVSS_kVideoEffectType_Green;
/**< we don't use any function context */
/*commented FB*/
/**
* We do not need to set the color context, it is already set during
sendCommand function */
}
if (M4xVSS_kVideoEffectType_Sepia ==
xVSS_context->pCurrentEditSettings->Effects[j].VideoEffectType)
{
xVSS_context->pCurrentEditSettings->Effects[j].ExtVideoEffectFct =
M4VSS3GPP_externalVideoEffectColor;
//xVSS_context->pSettings->Effects[j].pExtVideoEffectFctCtxt =
// (M4OSA_Void*)M4xVSS_kVideoEffectType_Sepia;
/**< we don't use any function context */
/*commented FB*/
/**
* We do not need to set the color context, it is already set during
sendCommand function */
}
if (M4xVSS_kVideoEffectType_Fifties ==
xVSS_context->pCurrentEditSettings->Effects[j].VideoEffectType)
{
xVSS_context->pCurrentEditSettings->Effects[j].ExtVideoEffectFct =
M4VSS3GPP_externalVideoEffectFifties;
/**
* We do not need to set the framing context, it is already set during
sendCommand function */
}
if (M4xVSS_kVideoEffectType_Negative ==
xVSS_context->pCurrentEditSettings->Effects[j].VideoEffectType)
{
xVSS_context->pCurrentEditSettings->Effects[j].ExtVideoEffectFct =
M4VSS3GPP_externalVideoEffectColor;
//xVSS_context->pSettings->Effects[j].pExtVideoEffectFctCtxt =
// (M4OSA_Void*)M4xVSS_kVideoEffectType_Negative;
/**< we don't use any function context */
/*commented FB*/
/**
* We do not need to set the color context, it is already set during
sendCommand function */
}
if (M4xVSS_kVideoEffectType_Framing ==
xVSS_context->pCurrentEditSettings->Effects[j].VideoEffectType)
{
xVSS_context->pCurrentEditSettings->Effects[j].ExtVideoEffectFct =
M4VSS3GPP_externalVideoEffectFraming;
/**
* We do not need to set the framing context, it is already set during
sendCommand function */
}
if (M4xVSS_kVideoEffectType_ZoomIn ==
xVSS_context->pSettings->Effects[j].VideoEffectType)
{
xVSS_context->pCurrentEditSettings->Effects[j].ExtVideoEffectFct =
M4VSS3GPP_externalVideoEffectZoom;
xVSS_context->pCurrentEditSettings->Effects[j].pExtVideoEffectFctCtxt =
(M4OSA_Void*)M4xVSS_kVideoEffectType_ZoomIn; /**< we don't use any
function context */
}
if (M4xVSS_kVideoEffectType_ZoomOut ==
xVSS_context->pCurrentEditSettings->Effects[j].VideoEffectType)
{
xVSS_context->pCurrentEditSettings->Effects[j].ExtVideoEffectFct =
M4VSS3GPP_externalVideoEffectZoom;
xVSS_context->pCurrentEditSettings->Effects[j].pExtVideoEffectFctCtxt =
(M4OSA_Void*)M4xVSS_kVideoEffectType_ZoomOut; /**< we don't use any
function context */
}
if (M4xVSS_kVideoEffectType_ColorRGB16 ==
xVSS_context->pCurrentEditSettings->Effects[j].VideoEffectType)
{
xVSS_context->pCurrentEditSettings->Effects[j].ExtVideoEffectFct =
M4VSS3GPP_externalVideoEffectColor;
//xVSS_context->pSettings->Effects[j].pExtVideoEffectFctCtxt =
// (M4OSA_Void*)M4xVSS_kVideoEffectType_ColorRGB16;
/**< we don't use any function context */
/**
* We do not need to set the color context, it is already set during
sendCommand function */
}
if (M4xVSS_kVideoEffectType_Gradient ==
xVSS_context->pCurrentEditSettings->Effects[j].VideoEffectType)
{
xVSS_context->pCurrentEditSettings->Effects[j].ExtVideoEffectFct =
M4VSS3GPP_externalVideoEffectColor;
//xVSS_context->pSettings->Effects[j].pExtVideoEffectFctCtxt =
// (M4OSA_Void*)M4xVSS_kVideoEffectType_ColorRGB16;
/**< we don't use any function context */
/**
* We do not need to set the color context, it is already set during
sendCommand function */
}
}
}
/**
* Open the VSS 3GPP */
err = M4VSS3GPP_editOpen(pVssCtxt, xVSS_context->pCurrentEditSettings);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalGenerateEditedFile:\
M4VSS3GPP_editOpen returned 0x%x\n",err);
M4VSS3GPP_editCleanUp(pVssCtxt);
/**
* Set the VSS context to NULL */
xVSS_context->pCurrentEditContext = M4OSA_NULL;
return err;
}
/**
* Save VSS context to be able to close / free VSS later */
xVSS_context->pCurrentEditContext = pVssCtxt;
return M4NO_ERROR;
}
/**
******************************************************************************
* prototype M4OSA_ERR M4xVSS_internalCloseEditedFile(M4OSA_Context pContext)
*
* @brief This function cleans up VSS
* @note
* @param pContext (IN) The integrator own context
*
* @return M4NO_ERROR: No error
* @return M4ERR_PARAMETER: At least one of the function parameters is null
******************************************************************************
*/
M4OSA_ERR M4xVSS_internalCloseEditedFile(M4OSA_Context pContext)
{
M4xVSS_Context* xVSS_context = (M4xVSS_Context*)pContext;
M4VSS3GPP_EditContext pVssCtxt = xVSS_context->pCurrentEditContext;
M4OSA_ERR err;
if(xVSS_context->pCurrentEditContext != M4OSA_NULL)
{
/**
* Close the VSS 3GPP */
err = M4VSS3GPP_editClose(pVssCtxt);
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalCloseEditedFile:\
M4VSS3GPP_editClose returned 0x%x\n",err);
M4VSS3GPP_editCleanUp(pVssCtxt);
/**
* Set the VSS context to NULL */
xVSS_context->pCurrentEditContext = M4OSA_NULL;
return err;
}
/**
* Free this VSS3GPP edition instance */
err = M4VSS3GPP_editCleanUp(pVssCtxt);
/**
* Set the VSS context to NULL */
xVSS_context->pCurrentEditContext = M4OSA_NULL;
if (err != M4NO_ERROR)
{
M4OSA_TRACE1_1("M4xVSS_internalCloseEditedFile: \
M4VSS3GPP_editCleanUp returned 0x%x\n",err);
return err;
}
}