/*! ************************************************************************************* * \file erc_api.c * * \brief * External (still inside video decoder) interface for error concealment module * * \author * - Ari Hourunranta * - Viktor Varsa * - Ye-Kui Wang * ************************************************************************************* */ #include "global.h" #include "memalloc.h" #include "erc_api.h" /*! ************************************************************************ * \brief * Initinize the error concealment module ************************************************************************ */ void ercInit(VideoParameters *p_Vid, int pic_sizex, int pic_sizey, int flag) { ercClose(p_Vid, p_Vid->erc_errorVar); p_Vid->erc_object_list = (objectBuffer_t *) calloc((pic_sizex * pic_sizey) >> 6, sizeof(objectBuffer_t)); if (p_Vid->erc_object_list == NULL) no_mem_exit("ercInit: erc_object_list"); // the error concealment instance is allocated p_Vid->erc_errorVar = ercOpen(); // set error concealment ON ercSetErrorConcealment(p_Vid->erc_errorVar, flag); } /*! ************************************************************************ * \brief * Allocates data structures used in error concealment. *\return * The allocated ercVariables_t is returned. ************************************************************************ */ ercVariables_t *ercOpen( void ) { ercVariables_t *errorVar = NULL; errorVar = (ercVariables_t *)malloc( sizeof(ercVariables_t)); if ( errorVar == NULL ) no_mem_exit("ercOpen: errorVar"); errorVar->nOfMBs = 0; errorVar->segments = NULL; errorVar->currSegment = 0; errorVar->yCondition = NULL; errorVar->uCondition = NULL; errorVar->vCondition = NULL; errorVar->prevFrameYCondition = NULL; errorVar->concealment = 1; return errorVar; } /*! ************************************************************************ * \brief * Resets the variables used in error detection. * Should be called always when starting to decode a new frame. * \param errorVar * Variables for error concealment * \param nOfMBs * Number of macroblocks in a frame * \param numOfSegments * Estimated number of segments (memory reserved) * \param picSizeX * Width of the frame in pixels. ************************************************************************ */ void ercReset( ercVariables_t *errorVar, int nOfMBs, int numOfSegments, int picSizeX ) { if ( errorVar && errorVar->concealment ) { int i = 0; // If frame size has been changed if ( nOfMBs != errorVar->nOfMBs && errorVar->yCondition != NULL ) { free( errorVar->yCondition ); errorVar->yCondition = NULL; free( errorVar->prevFrameYCondition ); errorVar->prevFrameYCondition = NULL; free( errorVar->uCondition ); errorVar->uCondition = NULL; free( errorVar->vCondition ); errorVar->vCondition = NULL; free( errorVar->segments ); errorVar->segments = NULL; } // If the structures are uninitialized (first frame, or frame size is changed) if ( errorVar->yCondition == NULL ) { errorVar->segments = (ercSegment_t *)malloc( numOfSegments*sizeof(ercSegment_t) ); if ( errorVar->segments == NULL ) no_mem_exit("ercReset: errorVar->segments"); memset( errorVar->segments, 0, numOfSegments*sizeof(ercSegment_t)); errorVar->nOfSegments = numOfSegments; errorVar->yCondition = (int *)malloc( 4*nOfMBs*sizeof(int) ); if ( errorVar->yCondition == NULL ) no_mem_exit("ercReset: errorVar->yCondition"); errorVar->prevFrameYCondition = (int *)malloc( 4*nOfMBs*sizeof(int) ); if ( errorVar->prevFrameYCondition == NULL ) no_mem_exit("ercReset: errorVar->prevFrameYCondition"); errorVar->uCondition = (int *)malloc( nOfMBs*sizeof(int) ); if ( errorVar->uCondition == NULL ) no_mem_exit("ercReset: errorVar->uCondition"); errorVar->vCondition = (int *)malloc( nOfMBs*sizeof(int) ); if ( errorVar->vCondition == NULL ) no_mem_exit("ercReset: errorVar->vCondition"); errorVar->nOfMBs = nOfMBs; } else { // Store the yCondition struct of the previous frame int *tmp = errorVar->prevFrameYCondition; errorVar->prevFrameYCondition = errorVar->yCondition; errorVar->yCondition = tmp; } // Reset tables and parameters memset( errorVar->yCondition, 0, 4*nOfMBs*sizeof(*errorVar->yCondition)); memset( errorVar->uCondition, 0, nOfMBs*sizeof(*errorVar->uCondition)); memset( errorVar->vCondition, 0, nOfMBs*sizeof(*errorVar->vCondition)); if (errorVar->nOfSegments != numOfSegments) { free( errorVar->segments ); errorVar->segments = NULL; errorVar->segments = (ercSegment_t *)malloc( numOfSegments*sizeof(ercSegment_t) ); if ( errorVar->segments == NULL ) no_mem_exit("ercReset: errorVar->segments"); errorVar->nOfSegments = numOfSegments; } memset( errorVar->segments, 0, errorVar->nOfSegments*sizeof(ercSegment_t)); for ( ; i < errorVar->nOfSegments; i++ ) { errorVar->segments[i].fCorrupted = 1; //! mark segments as corrupted errorVar->segments[i].startMBPos = 0; errorVar->segments[i].endMBPos = nOfMBs - 1; } errorVar->currSegment = 0; errorVar->nOfCorruptedSegments = 0; } } /*! ************************************************************************ * \brief * Resets the variables used in error detection. * Should be called always when starting to decode a new frame. * \param p_Vid * VideoParameters variable * \param errorVar * Variables for error concealment ************************************************************************ */ void ercClose(VideoParameters *p_Vid, ercVariables_t *errorVar ) { if ( errorVar != NULL ) { if (errorVar->yCondition != NULL) { free( errorVar->segments ); free( errorVar->yCondition ); free( errorVar->uCondition ); free( errorVar->vCondition ); free( errorVar->prevFrameYCondition ); } free( errorVar ); errorVar = NULL; } if ( p_Vid && p_Vid->erc_object_list) { free(p_Vid->erc_object_list); p_Vid->erc_object_list=NULL; } } /*! ************************************************************************ * \brief * Sets error concealment ON/OFF. Can be invoked only between frames, not during a frame * \param errorVar * Variables for error concealment * \param value * New value ************************************************************************ */ void ercSetErrorConcealment( ercVariables_t *errorVar, int value ) { if ( errorVar != NULL ) errorVar->concealment = value; } /*! ************************************************************************ * \brief * Creates a new segment in the segment-list, and marks the start MB and bit position. * If the end of the previous segment was not explicitly marked by "ercStopSegment", * also marks the end of the previous segment. * If needed, it reallocates the segment-list for a larger storage place. * \param currMBNum * The MB number where the new slice/segment starts * \param segment * Segment/Slice No. counted by the caller * \param bitPos * Bitstream pointer: number of bits read from the buffer. * \param errorVar * Variables for error detector ************************************************************************ */ void ercStartSegment( int currMBNum, int segment, unsigned int bitPos, ercVariables_t *errorVar ) { if ( errorVar && errorVar->concealment ) { errorVar->currSegmentCorrupted = 0; errorVar->segments[ segment ].fCorrupted = 0; errorVar->segments[ segment ].startMBPos = currMBNum; } } /*! ************************************************************************ * \brief * Marks the end position of a segment. * \param currMBNum * The last MB number of the previous segment * \param segment * Segment/Slice No. counted by the caller * If (segment<0) the internal segment counter is used. * \param bitPos * Bitstream pointer: number of bits read from the buffer. * \param errorVar * Variables for error detector ************************************************************************ */ void ercStopSegment( int currMBNum, int segment, unsigned int bitPos, ercVariables_t *errorVar ) { if ( errorVar && errorVar->concealment ) { errorVar->segments[ segment ].endMBPos = currMBNum; //! Changed TO 12.11.2001 errorVar->currSegment++; } } /*! ************************************************************************ * \brief * Marks the current segment (the one which has the "currMBNum" MB in it) * as lost: all the blocks of the MBs in the segment as corrupted. * \param picSizeX * Width of the frame in pixels. * \param errorVar * Variables for error detector ************************************************************************ */ void ercMarkCurrSegmentLost(int picSizeX, ercVariables_t *errorVar ) { if ( errorVar && errorVar->concealment ) { int current_segment = errorVar->currSegment-1, j; if (errorVar->currSegmentCorrupted == 0) { errorVar->nOfCorruptedSegments++; errorVar->currSegmentCorrupted = 1; } for ( j = errorVar->segments[current_segment].startMBPos; j <= errorVar->segments[current_segment].endMBPos; j++ ) { errorVar->yCondition[MBNum2YBlock (j, 0, picSizeX)] = ERC_BLOCK_CORRUPTED; errorVar->yCondition[MBNum2YBlock (j, 1, picSizeX)] = ERC_BLOCK_CORRUPTED; errorVar->yCondition[MBNum2YBlock (j, 2, picSizeX)] = ERC_BLOCK_CORRUPTED; errorVar->yCondition[MBNum2YBlock (j, 3, picSizeX)] = ERC_BLOCK_CORRUPTED; errorVar->uCondition[j] = ERC_BLOCK_CORRUPTED; errorVar->vCondition[j] = ERC_BLOCK_CORRUPTED; } errorVar->segments[current_segment].fCorrupted = 1; } } /*! ************************************************************************ * \brief * Marks the current segment (the one which has the "currMBNum" MB in it) * as OK: all the blocks of the MBs in the segment as OK. * \param picSizeX * Width of the frame in pixels. * \param errorVar * Variables for error detector ************************************************************************ */ void ercMarkCurrSegmentOK(int picSizeX, ercVariables_t *errorVar ) { if ( errorVar && errorVar->concealment ) { int current_segment = errorVar->currSegment-1, j; // mark all the Blocks belonging to the segment as OK */ for ( j = errorVar->segments[current_segment].startMBPos; j <= errorVar->segments[current_segment].endMBPos; j++ ) { errorVar->yCondition[MBNum2YBlock (j, 0, picSizeX)] = ERC_BLOCK_OK; errorVar->yCondition[MBNum2YBlock (j, 1, picSizeX)] = ERC_BLOCK_OK; errorVar->yCondition[MBNum2YBlock (j, 2, picSizeX)] = ERC_BLOCK_OK; errorVar->yCondition[MBNum2YBlock (j, 3, picSizeX)] = ERC_BLOCK_OK; errorVar->uCondition[j] = ERC_BLOCK_OK; errorVar->vCondition[j] = ERC_BLOCK_OK; } errorVar->segments[current_segment].fCorrupted = 0; } } /*! ************************************************************************ * \brief * Marks the Blocks of the given component (YUV) of the current MB as concealed. * \param currMBNum * Selects the segment where this MB number is in. * \param comp * Component to mark (0:Y, 1:U, 2:V, <0:All) * \param picSizeX * Width of the frame in pixels. * \param errorVar * Variables for error detector ************************************************************************ */ void ercMarkCurrMBConcealed( int currMBNum, int comp, int picSizeX, ercVariables_t *errorVar ) { int setAll = 0; if ( errorVar && errorVar->concealment ) { if (comp < 0) { setAll = 1; comp = 0; } switch (comp) { case 0: errorVar->yCondition[MBNum2YBlock (currMBNum, 0, picSizeX)] = ERC_BLOCK_CONCEALED; errorVar->yCondition[MBNum2YBlock (currMBNum, 1, picSizeX)] = ERC_BLOCK_CONCEALED; errorVar->yCondition[MBNum2YBlock (currMBNum, 2, picSizeX)] = ERC_BLOCK_CONCEALED; errorVar->yCondition[MBNum2YBlock (currMBNum, 3, picSizeX)] = ERC_BLOCK_CONCEALED; if (!setAll) break; case 1: errorVar->uCondition[currMBNum] = ERC_BLOCK_CONCEALED; if (!setAll) break; case 2: errorVar->vCondition[currMBNum] = ERC_BLOCK_CONCEALED; } } }