/* * 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; heightpDecYuvWithEffect[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; heightpDecYuvWithEffect[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; heightpDecYuvWithEffect[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; heightpDecYuvWithEffect[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; heightpDecYuvWithEffect[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; heightpDecYuvWithEffect[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; heightpDecYuvData[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; heightpDecYuvData[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; heightpDecYuvData[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; }