/* | |
* 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 M4DECODER_Null.c | |
* @brief Implementation of the Null decoder public interface | |
* @note This file implements a "null" video decoder, i.e. a decoder | |
* that does nothing | |
************************************************************************* | |
*/ | |
#include "NXPSW_CompilerSwitches.h" | |
#include "M4OSA_Types.h" | |
#include "M4OSA_Debug.h" | |
#include "M4TOOL_VersionInfo.h" | |
#include "M4DA_Types.h" | |
#include "M4DECODER_Common.h" | |
#include "M4DECODER_Null.h" | |
/** | |
************************************************************************ | |
* NULL Video Decoder version information | |
************************************************************************ | |
*/ | |
/* CHANGE_VERSION_HERE */ | |
#define M4DECODER_NULL_MAJOR 1 | |
#define M4DECODER_NULL_MINOR 0 | |
#define M4DECODER_NULL_REVISION 0 | |
/** | |
************************************************************************ | |
* structure M4_VideoHandler_Context | |
* @brief Defines the internal context of a video decoder instance | |
* @note The context is allocated and freed by the video decoder | |
************************************************************************ | |
*/ | |
typedef struct { | |
void* m_pLibrary; // Core library identifier | |
M4OSA_Int32 m_DecoderId; // Core decoder identifier | |
M4OSA_Int32 m_RendererId; // Core renderer identifier | |
M4_VideoStreamHandler* m_pVideoStreamhandler; // Video stream description | |
M4_AccessUnit* m_pNextAccessUnitToDecode; // Access unit used to | |
// read and decode one frame | |
void* m_pUserData; // Pointer to any user data | |
M4READER_DataInterface* m_pReader; // Reader data interface | |
M4OSA_Bool m_bDoRendering; // Decides if render required | |
M4OSA_Int32 m_structSize; // Size of the structure | |
M4DECODER_OutputFilter* m_pVideoFilter; // Color conversion filter | |
M4VIFI_ImagePlane *pDecYuvData; // Pointer to Yuv data plane | |
M4VIFI_ImagePlane *pDecYuvWithEffect; // Pointer to Yuv plane with color effect | |
M4OSA_Bool bYuvWithEffectSet; // Original Yuv data OR Yuv with color effect | |
} M4_VideoHandler_Context; | |
/***********************************************************************/ | |
/************** M4DECODER_VideoInterface implementation ****************/ | |
/***********************************************************************/ | |
/** | |
************************************************************************ | |
* @brief Creates an instance of the decoder | |
* @note Allocates the context | |
* | |
* @param pContext: (OUT) Context of the decoder | |
* @param pStreamHandler: (IN) Pointer to a video stream description | |
* @param pSrcInterface: (IN) Pointer to the M4READER_DataInterface | |
* structure that must be used by the | |
* decoder to read data from the stream | |
* @param pAccessUnit (IN) Pointer to an access unit | |
* (allocated by the caller) where decoded data | |
* are stored | |
* | |
* @return M4NO_ERROR There is no error | |
* @return M4ERR_STATE State automaton is not applied | |
* @return M4ERR_ALLOC A memory allocation has failed | |
* @return M4ERR_PARAMETER At least one input parameter is not proper | |
************************************************************************ | |
*/ | |
M4OSA_ERR M4DECODER_NULL_create(M4OSA_Context *pContext, | |
M4_StreamHandler *pStreamHandler, | |
M4READER_GlobalInterface *pReaderGlobalInterface, | |
M4READER_DataInterface *pReaderDataInterface, | |
M4_AccessUnit* pAccessUnit, | |
M4OSA_Void* pUserData) { | |
M4_VideoHandler_Context* pStreamContext = M4OSA_NULL; | |
*pContext = M4OSA_NULL; | |
pStreamContext = (M4_VideoHandler_Context*)M4OSA_32bitAlignedMalloc ( | |
sizeof(M4_VideoHandler_Context), M4DECODER_MPEG4, | |
(M4OSA_Char *)"M4_VideoHandler_Context"); | |
if (pStreamContext == 0) { | |
return M4ERR_ALLOC; | |
} | |
pStreamContext->m_structSize = sizeof(M4_VideoHandler_Context); | |
pStreamContext->m_pNextAccessUnitToDecode = M4OSA_NULL; | |
pStreamContext->m_pLibrary = M4OSA_NULL; | |
pStreamContext->m_pVideoStreamhandler = M4OSA_NULL; | |
pStreamContext->m_DecoderId = -1; | |
pStreamContext->m_RendererId = -1; | |
pStreamContext->m_pUserData = M4OSA_NULL; | |
pStreamContext->m_bDoRendering = M4OSA_TRUE; | |
pStreamContext->m_pVideoFilter = M4OSA_NULL; | |
pStreamContext->bYuvWithEffectSet = M4OSA_FALSE; | |
*pContext=pStreamContext; | |
return M4NO_ERROR; | |
} | |
/** | |
************************************************************************ | |
* @brief Destroy the instance of the decoder | |
* @note After this call the context is invalid | |
* | |
* @param context: (IN) Context of the decoder | |
* | |
* @return M4NO_ERROR There is no error | |
* @return M4ERR_PARAMETER The context is invalid | |
************************************************************************ | |
*/ | |
M4OSA_ERR M4DECODER_NULL_destroy(M4OSA_Context pContext) { | |
M4_VideoHandler_Context* pStreamContext = (M4_VideoHandler_Context*)pContext; | |
M4OSA_DEBUG_IF1((M4OSA_NULL == pStreamContext), | |
M4ERR_PARAMETER, "M4DECODER_NULL_destroy: invalid context pointer"); | |
free(pStreamContext); | |
return M4NO_ERROR; | |
} | |
/** | |
************************************************************************ | |
* @brief Get an option value from the decoder | |
* @note This function allows the caller to retrieve a property value: | |
* | |
* @param context: (IN) Context of the decoder | |
* @param optionId: (IN) Indicates the option to get | |
* @param pValue: (IN/OUT) Pointer to structure or value where | |
* option is stored | |
* | |
* @return M4NO_ERROR There is no error | |
* @return M4ERR_PARAMETER The context is invalid (in DEBUG only) | |
* @return M4ERR_BAD_OPTION_ID When the option ID is not a valid one | |
* @return M4ERR_STATE State automaton is not applied | |
* @return M4ERR_NOT_IMPLEMENTED Function not implemented | |
************************************************************************ | |
*/ | |
M4OSA_ERR M4DECODER_NULL_getOption(M4OSA_Context context, | |
M4OSA_OptionID optionId, | |
M4OSA_DataOption pValue) { | |
return M4ERR_NOT_IMPLEMENTED; | |
} | |
/** | |
************************************************************************ | |
* @brief Set an option value of the decoder | |
* @note Allows the caller to set a property value: | |
* | |
* @param context: (IN) Context of the decoder | |
* @param optionId: (IN) Identifier indicating the option to set | |
* @param pValue: (IN) Pointer to structure or value | |
* where option is stored | |
* | |
* @return M4NO_ERROR There is no error | |
* @return M4ERR_BAD_OPTION_ID The option ID is not a valid one | |
* @return M4ERR_STATE State automaton is not applied | |
* @return M4ERR_PARAMETER The option parameter is invalid | |
************************************************************************ | |
*/ | |
M4OSA_ERR M4DECODER_NULL_setOption(M4OSA_Context context, | |
M4OSA_OptionID optionId, | |
M4OSA_DataOption pValue) { | |
M4DECODER_OutputFilter *pFilterOption; | |
M4_VideoHandler_Context *pStreamContext = | |
(M4_VideoHandler_Context*)context; | |
M4OSA_ERR err = M4NO_ERROR; | |
M4OSA_UInt32 height = 0; | |
M4OSA_UInt8 *p_src,*p_des; | |
M4VIFI_ImagePlane* pTempDecYuvData = M4OSA_NULL; | |
switch (optionId) { | |
case M4DECODER_kOptionID_DecYuvData: | |
pStreamContext->pDecYuvData = (M4VIFI_ImagePlane *)pValue; | |
break; | |
case M4DECODER_kOptionID_YuvWithEffectContiguous: | |
pStreamContext->pDecYuvWithEffect = (M4VIFI_ImagePlane *)pValue; | |
break; | |
case M4DECODER_kOptionID_EnableYuvWithEffect: | |
pStreamContext->bYuvWithEffectSet = (M4OSA_Bool)pValue; | |
break; | |
case M4DECODER_kOptionID_YuvWithEffectNonContiguous: | |
pTempDecYuvData = (M4VIFI_ImagePlane *)pValue; | |
p_des = pStreamContext->pDecYuvWithEffect[0].pac_data + | |
pStreamContext->pDecYuvWithEffect[0].u_topleft; | |
p_src = pTempDecYuvData[0].pac_data + | |
pTempDecYuvData[0].u_topleft; | |
for (height = 0; height<pStreamContext->pDecYuvWithEffect[0].u_height; | |
height++) { | |
memcpy((void *)p_des, (void *)p_src, | |
pStreamContext->pDecYuvWithEffect[0].u_width); | |
p_des += pStreamContext->pDecYuvWithEffect[0].u_stride; | |
p_src += pTempDecYuvData[0].u_stride; | |
} | |
p_des = pStreamContext->pDecYuvWithEffect[1].pac_data + | |
pStreamContext->pDecYuvWithEffect[1].u_topleft; | |
p_src = pTempDecYuvData[1].pac_data + | |
pTempDecYuvData[1].u_topleft; | |
for (height = 0; height<pStreamContext->pDecYuvWithEffect[1].u_height; | |
height++) { | |
memcpy((void *)p_des, (void *)p_src, | |
pStreamContext->pDecYuvWithEffect[1].u_width); | |
p_des += pStreamContext->pDecYuvWithEffect[1].u_stride; | |
p_src += pTempDecYuvData[1].u_stride; | |
} | |
p_des = pStreamContext->pDecYuvWithEffect[2].pac_data + | |
pStreamContext->pDecYuvWithEffect[2].u_topleft; | |
p_src = pTempDecYuvData[2].pac_data + | |
pTempDecYuvData[2].u_topleft; | |
for (height = 0; height<pStreamContext->pDecYuvWithEffect[2].u_height; | |
height++) { | |
memcpy((void *)p_des, (void *)p_src, | |
pStreamContext->pDecYuvWithEffect[2].u_width); | |
p_des += pStreamContext->pDecYuvWithEffect[2].u_stride; | |
p_src += pTempDecYuvData[2].u_stride; | |
} | |
break; | |
case M4DECODER_kOptionID_OutputFilter: | |
pFilterOption = (M4DECODER_OutputFilter*)pValue; | |
break; | |
case M4DECODER_kOptionID_DeblockingFilter: | |
err = M4ERR_BAD_OPTION_ID; | |
break; | |
default: | |
err = M4ERR_BAD_OPTION_ID; | |
break; | |
} | |
return err; | |
} | |
/** | |
************************************************************************ | |
* @brief Decode video Access Units up to a target time | |
* @note Parse and decode the video until it can output a decoded image | |
* for which the composition time is equal or greater to the | |
* passed targeted time. | |
* The data are read from the reader data interface passed to | |
* M4DECODER_MPEG4_create. | |
* | |
* @param context: (IN) Context of the decoder | |
* @param pTime: (IN/OUT) IN: Time to decode up to (in msec) | |
* OUT:Time of the last decoded frame (in msec) | |
* @param bJump: (IN) 0 if no jump occured just before this call | |
* 1 if a a jump has just been made | |
* @return M4NO_ERROR there is no error | |
* @return M4ERR_PARAMETER at least one parameter is not properly set | |
* @return M4WAR_NO_MORE_AU there is no more access unit to decode (EOS) | |
************************************************************************ | |
*/ | |
M4OSA_ERR M4DECODER_NULL_decode(M4OSA_Context context, | |
M4_MediaTime* pTime, M4OSA_Bool bJump, | |
M4OSA_UInt32 tolerance) { | |
// Do nothing; input time stamp itself returned | |
return M4NO_ERROR; | |
} | |
/** | |
************************************************************************ | |
* @brief Renders the video at the specified time. | |
* @note | |
* @param context: (IN) Context of the decoder | |
* @param pTime: (IN/OUT) IN: Time to render to (in msecs) | |
* OUT:Time of the rendered frame (in ms) | |
* @param pOutputPlane:(OUT) Output plane filled with decoded data | |
* @param bForceRender:(IN) 1 if the image must be rendered even it | |
* has been rendered already | |
* 0 if not | |
* | |
* @return M4NO_ERROR There is no error | |
* @return M4ERR_PARAMETER At least one parameter is not properly set | |
* @return M4ERR_STATE State automaton is not applied | |
* @return M4ERR_ALLOC There is no more available memory | |
* @return M4WAR_VIDEORENDERER_NO_NEW_FRAME If the frame has already been rendered | |
************************************************************************ | |
*/ | |
M4OSA_ERR M4DECODER_NULL_render(M4OSA_Context context, M4_MediaTime* pTime, | |
M4VIFI_ImagePlane* pOutputPlane, | |
M4OSA_Bool bForceRender) { | |
M4OSA_ERR err = M4NO_ERROR; | |
M4OSA_UInt32 height; | |
M4OSA_UInt8 *p_src,*p_des; | |
M4_VideoHandler_Context* pStreamContext = | |
(M4_VideoHandler_Context*)context; | |
if (pStreamContext->bYuvWithEffectSet == M4OSA_TRUE) { | |
p_des = pOutputPlane[0].pac_data + pOutputPlane[0].u_topleft; | |
p_src = pStreamContext->pDecYuvWithEffect[0].pac_data + | |
pStreamContext->pDecYuvWithEffect[0].u_topleft; | |
for (height = 0; height<pOutputPlane[0].u_height; height++) { | |
memcpy((void *)p_des, (void *)p_src, pOutputPlane[0].u_width); | |
p_des += pOutputPlane[0].u_stride; | |
p_src += pStreamContext->pDecYuvWithEffect[0].u_stride; | |
} | |
p_des = pOutputPlane[1].pac_data + pOutputPlane[1].u_topleft; | |
p_src = pStreamContext->pDecYuvWithEffect[1].pac_data + | |
pStreamContext->pDecYuvWithEffect[1].u_topleft; | |
for (height = 0; height<pOutputPlane[1].u_height; height++) { | |
memcpy((void *)p_des, (void *)p_src, pOutputPlane[1].u_width); | |
p_des += pOutputPlane[1].u_stride; | |
p_src += pStreamContext->pDecYuvWithEffect[1].u_stride; | |
} | |
p_des = pOutputPlane[2].pac_data + pOutputPlane[2].u_topleft; | |
p_src = pStreamContext->pDecYuvWithEffect[2].pac_data + | |
pStreamContext->pDecYuvWithEffect[2].u_topleft; | |
for (height = 0; height<pOutputPlane[2].u_height; height++) { | |
memcpy((void *)p_des, (void *)p_src, pOutputPlane[2].u_width); | |
p_des += pOutputPlane[2].u_stride; | |
p_src += pStreamContext->pDecYuvWithEffect[2].u_stride; | |
} | |
} else { | |
p_des = pOutputPlane[0].pac_data + pOutputPlane[0].u_topleft; | |
p_src = pStreamContext->pDecYuvData[0].pac_data + | |
pStreamContext->pDecYuvData[0].u_topleft; | |
for (height = 0; height<pOutputPlane[0].u_height; height++) { | |
memcpy((void *)p_des, (void *)p_src, pOutputPlane[0].u_width); | |
p_des += pOutputPlane[0].u_stride; | |
p_src += pStreamContext->pDecYuvData[0].u_stride; | |
} | |
p_des = pOutputPlane[1].pac_data + pOutputPlane[1].u_topleft; | |
p_src = pStreamContext->pDecYuvData[1].pac_data + | |
pStreamContext->pDecYuvData[1].u_topleft; | |
for (height = 0; height<pOutputPlane[1].u_height; height++) { | |
memcpy((void *)p_des, (void *)p_src, pOutputPlane[1].u_width); | |
p_des += pOutputPlane[1].u_stride; | |
p_src += pStreamContext->pDecYuvData[1].u_stride; | |
} | |
p_des = pOutputPlane[2].pac_data + pOutputPlane[2].u_topleft; | |
p_src = pStreamContext->pDecYuvData[2].pac_data + | |
pStreamContext->pDecYuvData[2].u_topleft; | |
for (height = 0; height<pOutputPlane[2].u_height; height++) { | |
memcpy((void *)p_des,(void *)p_src,pOutputPlane[2].u_width); | |
p_des += pOutputPlane[2].u_stride; | |
p_src += pStreamContext->pDecYuvData[2].u_stride; | |
} | |
} | |
return err; | |
} | |
/** | |
************************************************************************ | |
* @brief Retrieves the interface implemented by the decoder | |
* @param pDecoderType : Pointer to a M4DECODER_VideoType | |
* (allocated by the caller) | |
* that will be filled with the decoder type | |
* @param pDecoderInterface : Address of a pointer that will be set to | |
* the interface implemented by this decoder. | |
* The interface is a structure allocated by | |
* this function and must be freed by the caller. | |
* | |
* @returns : M4NO_ERROR if OK | |
* M4ERR_ALLOC if allocation failed | |
************************************************************************ | |
*/ | |
M4OSA_ERR M4DECODER_NULL_getInterface (M4DECODER_VideoType *pDecoderType, | |
M4DECODER_VideoInterface **pDecoderInterface) { | |
*pDecoderInterface = | |
(M4DECODER_VideoInterface*)M4OSA_32bitAlignedMalloc( | |
sizeof(M4DECODER_VideoInterface), | |
M4DECODER_MPEG4, (M4OSA_Char *)"M4DECODER_VideoInterface"); | |
if (M4OSA_NULL == *pDecoderInterface) { | |
return M4ERR_ALLOC; | |
} | |
*pDecoderType = M4DECODER_kVideoTypeYUV420P; | |
(*pDecoderInterface)->m_pFctCreate = M4DECODER_NULL_create; | |
(*pDecoderInterface)->m_pFctDestroy = M4DECODER_NULL_destroy; | |
(*pDecoderInterface)->m_pFctGetOption = M4DECODER_NULL_getOption; | |
(*pDecoderInterface)->m_pFctSetOption = M4DECODER_NULL_setOption; | |
(*pDecoderInterface)->m_pFctDecode = M4DECODER_NULL_decode; | |
(*pDecoderInterface)->m_pFctRender = M4DECODER_NULL_render; | |
return M4NO_ERROR; | |
} |