--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/videoeditorengine/h263decoder/src/decvp_mpeg.cpp Fri Jan 29 14:08:33 2010 +0200
@@ -0,0 +1,653 @@
+/*
+* Copyright (c) 2010 Ixonos Plc.
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - Initial contribution
+*
+* Contributors:
+* Ixonos Plc
+*
+* Description:
+* Video packet decoding module (MPEG-4).
+*
+*/
+
+
+/*
+ * Includes
+ */
+#include "h263dConfig.h"
+#include "decvp_mpeg.h"
+#include "block.h"
+#include "debug.h"
+#include "decmbs.h"
+#include "stckheap.h"
+#include "sync.h"
+#include "viddemux.h"
+#include "biblin.h"
+/* MVE */
+#include "MPEG4Transcoder.h"
+
+/*
+ * Global functions
+ */
+
+/* {{-output"dvpGetAndDecodeVideoPacketHeader.txt"}} */
+/*
+ * dvpGetAndDecodeVideoPacketHeader
+ *
+ *
+ * Parameters:
+ * inParam input parameters
+ * inOutParam input/output parameters, these parameters
+ * may be modified in the function
+ *
+ * Function:
+ * This function gets and decodes a Video Packet header at the
+ * current position of the bit buffer. It checks its correctness and
+ * if it fits to the sequence of VPs, and does the necessary actions for
+ * correction.
+ *
+ * Returns:
+ * >= 0 the function was successful
+ * < 0 an error occured
+ *
+ */
+
+int dvpGetAndDecodeVideoPacketHeader(
+ const dvpVPInParam_t *inParam,
+ dvpVPInOutParam_t *inOutParam)
+/* {{-output"dvpGetAndDecodeVideoPacketHeader.txt"}} */
+{
+ int16 error = 0;
+ vdxGetVideoPacketHeaderInputParam_t vdxParam;
+ vdxVideoPacketHeader_t header;
+ bibBuffer_t *inBuffer = inParam->inBuffer;
+ int bitErrorIndication = 0, retVal, fLostSegment = FALSE;
+
+ /*
+ * Get VP header
+ */
+
+ vdxParam.fcode_forward = inParam->pictParam->fcode_forward;
+ vdxParam.time_increment_resolution = inParam->pictParam->time_increment_resolution;
+ vdxParam.numOfMBs = inParam->pictParam->numMBsInGOB;
+
+ retVal = vdxGetVideoPacketHeader(inBuffer, &vdxParam, &header, &bitErrorIndication);
+ if (retVal < 0) {
+ return DGOB_ERR;
+ } else if (retVal > 0) {
+ deb("dvpGetAndDecodeVideoPacketHeader: ERROR - vdxGetVideoPacketHeader failed.\n");
+ goto headerFailure;
+ }
+
+
+ /*
+ * Check header validity
+ */
+
+ if (header.currMBNum == 0 || header.currMBNum >= inParam->pictParam->numMBsInGOB) {
+ deb("dvpGetAndDecodeVideoPacketHeader: ERROR - too big currMBNum.\n");
+ goto headerFailure;
+ }
+
+ /* quant can not be zero */
+ if(header.quant == 0) {
+ goto headerFailure;
+ }
+
+ if (header.fHEC) {
+
+ if (header.time_base_incr < 0 || header.time_base_incr > 60) {
+ if (bitErrorIndication) {
+ goto headerFailure;
+ }
+ }
+
+ /* fcode can have only the valid values 1..7 */
+ if (header.coding_type == VDX_VOP_TYPE_P)
+ if (header.fcode_forward == 0) {
+ goto headerFailure;
+ }
+
+ if (!inParam->fVOPHeaderCorrupted) {
+
+ if ((inParam->pictParam->pictureType != header.coding_type) ||
+ (inParam->pictParam->time_base_incr != header.time_base_incr) ||
+ (inParam->pictParam->time_inc != header.time_inc)) {
+ deb("dvpGetAndDecodeVideoPacketHeader: ERROR - Parameter change VOP<->VP header.\n");
+ goto headerFailure;
+ }
+ }
+ }
+ if (inParam->fVOPHeaderCorrupted) {
+ /* Get the coding type parameter since it is needed in the concealment before the other updates */
+ if (header.fHEC) {
+ inParam->pictParam->pictureType = header.coding_type;
+ }
+ }
+ if (header.currMBNum != inOutParam->currMBNum) {
+ if ( header.currMBNum > inOutParam->currMBNum && bitErrorIndication == 0) {
+
+ fLostSegment = TRUE;
+ goto headerFailure;
+
+ } else if (header.currMBNum < inOutParam->currMBNum) {
+ deb("dvpGetAndDecodeVideoPacketHeader: ERROR - MB counting is out of sync.\n");
+ goto headerFailure;
+ }
+ }
+
+ /*
+ * Update parameters
+ */
+
+ inOutParam->currMBNum = header.currMBNum;
+ inOutParam->quant = header.quant;
+
+ if (inParam->fVOPHeaderCorrupted) {
+ if (header.fHEC) {
+ inParam->pictParam->mod_time_base += inParam->pictParam->time_base_incr = header.time_base_incr;
+
+ inParam->pictParam->time_inc = header.time_inc;
+
+ inOutParam->frameNum = (int) ((inParam->pictParam->mod_time_base +
+ ((double) header.time_inc) / ((double) inParam->pictParam->time_increment_resolution)) *
+ 30.0 + 0.001);
+
+ inParam->pictParam->tr = inOutParam->frameNum % 256;
+ inParam->pictParam->pictureType = header.coding_type;
+
+ inParam->pictParam->intra_dc_vlc_thr = header.intra_dc_vlc_thr;
+
+ if (header.coding_type == VDX_VOP_TYPE_P)
+ if (inParam->pictParam->fcode_forward != header.fcode_forward) {
+ /* Initialize once to count parameters for the mvc module */
+ int r_size, scale_factor;
+
+ inParam->pictParam->fcode_forward = header.fcode_forward;
+
+ inOutParam->mvcData->f_code = inParam->pictParam->fcode_forward;
+ r_size = inParam->pictParam->fcode_forward - 1;
+ scale_factor = (1 << r_size);
+ inOutParam->mvcData->range = 160 * scale_factor;
+ }
+ } else {
+ /* seek next PSC, VP start code is not good enough */
+ sncRewindAndSeekNewMPEGSync(-1, inBuffer, 0, &error);
+ return DGOB_OK_BUT_BIT_ERROR;
+ }
+ }
+
+ if (fLostSegment)
+ return DGOB_OK_BUT_BIT_ERROR;
+ else
+ return DGOB_OK;
+
+ headerFailure:
+ sncRewindAndSeekNewMPEGSync(-1, inBuffer, inParam->pictParam->fcode_forward, &error);
+
+ if (error && error != ERR_BIB_NOT_ENOUGH_DATA)
+ return DGOB_ERR;
+ return DGOB_OK_BUT_BIT_ERROR;
+}
+
+
+/* {{-output"dvpGetAndDecodeVideoPacketContents.txt"}} */
+/*
+ * dvpGetAndDecodeVideoPacketContents
+ *
+ *
+ * Parameters:
+ * inParam input parameters
+ * fGetNewReferenceFrame non-zero if a new reference frame must be
+ * requested from the image store, otherwise 0
+ * inOutParam input/output parameters, these parameters
+ * may be modified in the function
+ *
+ * Function:
+ * This function gets and decodes the contents of a Video Packet
+ * after the header of the VP (either VP header or picture
+ * header) is already got and processed. It works MB-by-MB or if VP
+ * is data partitioned calls the corresponding decoding functions.
+ * Error concealment for the missing (not decodable) MBs in a P-frame
+ * is called.
+ *
+ * Returns:
+ * >= 0 the function was successful
+ * < 0 an error occured
+ *
+ */
+
+int dvpGetAndDecodeVideoPacketContents(
+ const dvpVPInParam_t *inParam,
+ int fGetNewReferenceFrame,
+ dvpVPInOutParam_t *inOutParam, CMPEG4Transcoder *hTranscoder)
+/* {{-output"dvpGetAndDecodeVideoPacketContents.txt"}} */
+{
+ int16 error = 0;
+ int bitErrorIndication = 0;
+ dmbPFrameMBInParam_t dpmbi;
+ dmbPFrameMBInOutParam_t dpmbio;
+ dmbIFrameMBInParam_t dimbi;
+ dmbIFrameMBInOutParam_t dimbio;
+ int yPosInMBs, xPosInMBs = 0;
+ bibBuffer_t *inBuffer;
+ bibBuffer_t
+ *outBuffer; /* Output bit buffer instance */
+
+ bibBufferEdit_t
+ *bufEdit;
+
+ int colorEffect;
+ TBool getDecodedFrame;
+
+
+ int fSegmentCorrupted = 0;
+
+ int dmbRetValue;
+ int sncCode = SNC_NO_SYNC;
+ int lastMBNumInVP = 0;
+ int startMB = inOutParam->currMBNum;
+
+ SOH_DEFINE(blcDiffMB_t, pDiffMB); /* Storage for the previous difference blocks */
+
+ SOH_ALLOC(blcDiffMB_t, pDiffMB);
+
+ if (pDiffMB == NULL) {
+ deb("dvpGetAndDecodeVideoPacketContents: SOH_ALLOC failed.\n");
+ goto unexpectedError;
+ }
+
+ pDiffMB->cbpy = 0;
+
+ inBuffer = inParam->inBuffer;
+ outBuffer = inParam->outBuffer;
+ bufEdit = inParam->bufEdit;
+ colorEffect = inParam->iColorEffect;
+ getDecodedFrame = inParam->iGetDecodedFrame;
+
+ /* If the reference frame changed */
+ if (fGetNewReferenceFrame) {
+ vdeIms_t *store = inOutParam->imageStore;
+ vdeImsItem_t *imsItem;
+ vdeImb_t *imb;
+ int width, height;
+
+ if (vdeImsGetReference(store, VDEIMS_REF_LATEST, 0, &imsItem) < 0) {
+ deb("dvpGetAndDecodeVideoPacketContents: ERROR - vdeImsGetReference "
+ "failed.\n");
+ goto unexpectedError;
+ }
+
+ /* If no reference frame available */
+ if (!imsItem) {
+ /* Treat the situation like a decoding error.*/
+ deb("dvpGetAndDecodeVideoPacketContents: Warning - no reference frame "
+ "available.\n");
+ goto headerFailure;
+ }
+
+ if (vdeImsStoreItemToImageBuffer(imsItem, &imb) < 0) {
+ deb("dvpGetAndDecodeVideoPacketContents: ERROR - vdeImsStoreItemToImageBuffer "
+ "failed.\n");
+ goto unexpectedError;
+ }
+
+ if (vdeImbYUV(imb, &inOutParam->refY, &inOutParam->refU,
+ &inOutParam->refV, &width, &height) < 0) {
+ deb("dvpGetAndDecodeVideoPacketContents: ERROR - vdeImbYUV "
+ "failed.\n");
+ goto unexpectedError;
+ }
+ }
+
+ xPosInMBs = (inOutParam->currMBNum % inParam->pictParam->numMBsInMBLine);
+ yPosInMBs = (inOutParam->currMBNum / inParam->pictParam->numMBsInMBLine);
+
+ /* if VOP header corrupted and first VP -> exit */
+ if(inParam->fVOPHeaderCorrupted && inOutParam->currMBNum==0) {
+ fSegmentCorrupted = 1;
+ goto exitWhenVOPHeaderCorrupted;
+ }
+
+ /* in case of an I-VOP */
+ if (inParam->pictParam->pictureType == VDX_VOP_TYPE_I) {
+ dimbi.inBuffer = inBuffer;
+ dimbi.outBuffer = outBuffer;
+ dimbi.bufEdit = bufEdit;
+ dimbi.iColorEffect = colorEffect;
+ dimbi.iGetDecodedFrame = getDecodedFrame;
+
+ dimbi.pictParam = inParam->pictParam;
+
+ dimbi.xPosInMBs = xPosInMBs;
+ dimbi.yPosInMBs = yPosInMBs;
+
+ dimbio.currMBNum = inOutParam->currMBNum;
+ dimbio.currMBNumInVP = 0;
+
+ dimbio.aicData = inOutParam->aicData;
+
+ dimbio.fCodedMBs = inOutParam->fCodedMBs;
+ dimbio.numOfCodedMBs = inOutParam->numOfCodedMBs;
+ dimbio.quant = inOutParam->quant;
+
+ /* YUV pointers */
+ {
+ int32 yOffset, uvOffset;
+
+ yOffset = inParam->pictParam->lumMemWidth * dimbi.yPosInMBs + dimbi.xPosInMBs;
+ uvOffset = (inParam->pictParam->lumMemWidth >> 1) * dimbi.yPosInMBs + dimbi.xPosInMBs;
+
+ if ( inOutParam->currPY != NULL )
+ {
+ dimbio.yMBInFrame = inOutParam->currPY + (yOffset << 4);
+ dimbio.uBlockInFrame = inOutParam->currPU + (uvOffset << 3);
+ dimbio.vBlockInFrame = inOutParam->currPV + (uvOffset << 3);
+ }
+ else
+ {
+ dimbio.yMBInFrame = NULL;
+ dimbio.uBlockInFrame = NULL;
+ dimbio.vBlockInFrame = NULL;
+ }
+ }
+ }
+ /* in case of a P-VOP */
+ else {
+ dpmbi.inBuffer = inBuffer;
+ dpmbi.outBuffer = outBuffer;
+ dpmbi.bufEdit = bufEdit;
+ dpmbi.iColorEffect = colorEffect;
+ dpmbi.iGetDecodedFrame = getDecodedFrame;
+
+ dpmbi.pictParam = inParam->pictParam;
+
+ dpmbi.xPosInMBs = xPosInMBs;
+ dpmbi.yPosInMBs = yPosInMBs;
+
+ dpmbi.refY = inOutParam->refY;
+ dpmbi.refU = inOutParam->refU;
+ dpmbi.refV = inOutParam->refV;
+ dpmbi.currPY = inOutParam->currPY;
+ dpmbi.currPU = inOutParam->currPU;
+ dpmbi.currPV = inOutParam->currPV;
+
+ dpmbio.currMBNum = inOutParam->currMBNum;
+ dpmbio.currMBNumInVP = 0;
+
+ dpmbio.fCodedMBs = inOutParam->fCodedMBs;
+ dpmbio.numOfCodedMBs = inOutParam->numOfCodedMBs;
+ dpmbio.quant = inOutParam->quant;
+
+ dpmbio.aicData = inOutParam->aicData;
+
+ dpmbio.mvcData = inOutParam->mvcData;
+ dpmbio.diffMB = pDiffMB;
+
+ /* YUV pointers */
+ {
+ int32 yOffset, uvOffset;
+
+ yOffset = inParam->pictParam->lumMemWidth * dpmbi.yPosInMBs + dpmbi.xPosInMBs;
+ uvOffset = (inParam->pictParam->lumMemWidth >> 1) * dpmbi.yPosInMBs + dpmbi.xPosInMBs;
+
+ if ( inOutParam->currPY != NULL )
+ {
+ dpmbio.yMBInFrame = inOutParam->currPY + (yOffset << 4);
+ dpmbio.uBlockInFrame = inOutParam->currPU + (uvOffset << 3);
+ dpmbio.vBlockInFrame = inOutParam->currPV + (uvOffset << 3);
+ }
+ else
+ {
+ dimbio.yMBInFrame = NULL;
+ dimbio.uBlockInFrame = NULL;
+ dimbio.vBlockInFrame = NULL;
+ }
+ }
+ }
+
+ /* Decode multiple Macroblocks until a resync_marker is found or error occurs */
+ while (inParam->pictParam->numMBsInGOB != inOutParam->currMBNum &&
+ sncCode != SNC_VIDPACK && sncCode != SNC_VOP) {
+
+ /* MVE */
+ hTranscoder->BeginOneMB((inParam->pictParam->pictureType == VDX_VOP_TYPE_I) ? dimbio.currMBNum : dpmbio.currMBNum );
+
+ /* decode an I-frame MB */
+ if (inParam->pictParam->pictureType == VDX_VOP_TYPE_I) {
+
+ if(inParam->pictParam->data_partitioned) {
+
+ dmbRetValue = dmbsGetAndDecodeIMBsDataPartitioned(&dimbi, &dimbio,
+ inOutParam->quantParams, hTranscoder);
+
+ if (dmbRetValue < 0)
+ goto unexpectedError;
+
+ inOutParam->currMBNum = dimbio.currMBNum;
+
+ /* Video Packet corrupted */
+ if ( fSegmentCorrupted )
+ break;
+
+ } else {
+
+ dmbRetValue = dmbGetAndDecodeIFrameMB(&dimbi, &dimbio, 1, hTranscoder);
+
+ if (dmbRetValue < 0)
+ goto unexpectedError;
+ else if (dmbRetValue == DMB_BIT_ERR ) {
+ /* Video Packet corrupted */
+ fSegmentCorrupted = 1;
+ break;
+ }
+
+ /* Store quantizer */
+ inOutParam->quantParams[dimbio.currMBNum] = dimbio.quant;
+
+ /* increment the frame pointers and MB counters */
+ dimbio.currMBNum++;
+ dimbio.currMBNumInVP++;
+
+ if ( dimbio.yMBInFrame != NULL )
+ {
+ dimbio.yMBInFrame += 16;
+ dimbio.uBlockInFrame += 8;
+ dimbio.vBlockInFrame += 8;
+ }
+ dimbi.xPosInMBs++;
+
+ if (dimbi.xPosInMBs == inParam->pictParam->numMBsInMBLine) {
+ if ( dimbio.yMBInFrame != NULL )
+ {
+ dimbio.yMBInFrame += 15 * inParam->pictParam->lumMemWidth;
+ dimbio.uBlockInFrame += 7 * (inParam->pictParam->lumMemWidth >> 1);
+ dimbio.vBlockInFrame += 7 * (inParam->pictParam->lumMemWidth >> 1);
+ }
+ dimbi.xPosInMBs = 0;
+ dimbi.yPosInMBs++;
+ }
+
+ inOutParam->currMBNum = dimbio.currMBNum;
+ }
+
+ /* decode a P-frame MB */
+ } else {
+
+ if(inParam->pictParam->data_partitioned) {
+
+ dmbRetValue = dmbsGetAndDecodePMBsDataPartitioned(&dpmbi, &dpmbio,
+ inOutParam->quantParams, hTranscoder);
+
+ if (dmbRetValue < 0)
+ goto unexpectedError;
+
+ inOutParam->currMBNum = dpmbio.currMBNum;
+ lastMBNumInVP = dpmbio.currMBNumInVP;
+
+ /* Video Packet corrupted */
+ if ( fSegmentCorrupted )
+ break;
+
+ } else {
+
+ dmbRetValue = dmbGetAndDecodePFrameMB(&dpmbi, &dpmbio, 1, hTranscoder);
+
+ if (dmbRetValue < 0)
+ goto unexpectedError;
+ else if (dmbRetValue == DMB_BIT_ERR ) {
+ /* Video Packet corrupted */
+ fSegmentCorrupted = 1;
+ break;
+ }
+
+ /* Store quantizer */
+ inOutParam->quantParams[dpmbio.currMBNum] = dpmbio.quant;
+
+ /* increment the frame pointers and MB counters */
+ dpmbio.currMBNum++;
+ dpmbio.currMBNumInVP++;
+
+ if ( dpmbio.yMBInFrame != NULL )
+ {
+ dpmbio.yMBInFrame += 16;
+ dpmbio.uBlockInFrame += 8;
+ dpmbio.vBlockInFrame += 8;
+ }
+ dpmbi.xPosInMBs++;
+
+ if (dpmbi.xPosInMBs == inParam->pictParam->numMBsInMBLine) {
+ if ( dpmbio.yMBInFrame != NULL )
+ {
+ dpmbio.yMBInFrame += 15 * inParam->pictParam->lumMemWidth;
+ dpmbio.uBlockInFrame += 7 * (inParam->pictParam->lumMemWidth >> 1);
+ dpmbio.vBlockInFrame += 7 * (inParam->pictParam->lumMemWidth >> 1);
+ }
+ dpmbi.xPosInMBs = 0;
+ dpmbi.yPosInMBs++;
+ }
+
+ inOutParam->currMBNum = dpmbio.currMBNum;
+ }
+ }
+
+ /* check for a resync_marker */
+ sncCode = sncCheckMpegSync(inBuffer, inParam->pictParam->fcode_forward, &error);
+
+ /* If sncCheckMpegSync failed */
+ if (error && error != ERR_BIB_NOT_ENOUGH_DATA) {
+ deb1p("dvpGetAndDecodeVideoPacketContents: ERROR - sncCheckSync returned %d.\n", error);
+ goto unexpectedError;
+
+ } else
+ /* If buffer ends (in one-frame-per-one-buffer case) */
+ if (sncCode == SNC_EOB ||
+ sncCode == SNC_STUFFING ||
+ error == ERR_BIB_NOT_ENOUGH_DATA) {
+ break;
+ }
+
+ }
+
+
+// <--
+
+ inOutParam->numOfCodedMBs = (inParam->pictParam->pictureType != VDX_VOP_TYPE_I) ?
+ dpmbio.numOfCodedMBs : dimbio.numOfCodedMBs;
+
+ if (fSegmentCorrupted) {
+ u_int32 nextVPBitPos;
+
+ /* find the next resync marker, to get the number of MBs in the current VP */
+ sncCode = sncRewindAndSeekNewMPEGSync(-1, inBuffer, inParam->pictParam->fcode_forward, &error);
+ if (error && error != ERR_BIB_NOT_ENOUGH_DATA) {
+ goto unexpectedError;
+ } else if (sncCode == SNC_EOB) {
+ goto exitFunction;
+ }
+
+ nextVPBitPos = bibNumberOfFlushedBits(inParam->inBuffer);
+
+ /* if the lastMBNumInVP was not yet read */
+ if (inParam->pictParam->pictureType == VDX_VOP_TYPE_I ||
+ !inParam->pictParam->data_partitioned ||
+ lastMBNumInVP == 0) {
+
+ /* if VP header is found: read it, and get last MB number in current vop */
+ if (sncCode == SNC_VIDPACK) {
+ vdxVideoPacketHeader_t header;
+ vdxGetVideoPacketHeaderInputParam_t vdxParam;
+ int retValue;
+
+ vdxParam.fcode_forward = inParam->pictParam->fcode_forward;
+ vdxParam.time_increment_resolution = inParam->pictParam->time_increment_resolution;
+ vdxParam.numOfMBs = inParam->pictParam->numMBsInGOB;
+
+ retValue = vdxGetVideoPacketHeader(inParam->inBuffer, &vdxParam, &header, &bitErrorIndication);
+ if (retValue < 0) {
+ goto unexpectedError;
+ } else if (retValue == VDX_OK_BUT_BIT_ERROR) {
+ /* If bit error occurred */
+ goto headerFailure;
+ }
+
+ /* rewind the bits to the beginning of the VP header */
+ bibRewindBits(bibNumberOfFlushedBits(inParam->inBuffer) - nextVPBitPos,
+ inParam->inBuffer, &error);
+
+ lastMBNumInVP = header.currMBNum;
+
+ } else {
+ lastMBNumInVP = inParam->pictParam->numMBsInGOB;
+ }
+ }
+
+ /* if possibly the next VP header is damaged (it gives MB index which is smaller than the start of the current one */
+ if (lastMBNumInVP <= startMB || lastMBNumInVP > inParam->pictParam->numMBsInGOB)
+ goto exitFunction;
+
+ /* if the MB counting due to error overran the next VP header's value */
+ if (inOutParam->currMBNum > lastMBNumInVP)
+ inOutParam->currMBNum = VDC_MAX(lastMBNumInVP-3,startMB);
+
+ /* if not all the MBs have been predicted due to error */
+ else if (inOutParam->currMBNum < lastMBNumInVP)
+ inOutParam->currMBNum = VDC_MAX(inOutParam->currMBNum-1,startMB);
+
+
+ inOutParam->currMBNum = lastMBNumInVP;
+ }
+
+ exitFunction:
+
+
+ exitWhenVOPHeaderCorrupted:
+
+ if (!fSegmentCorrupted) {
+ SOH_DEALLOC(pDiffMB);
+ return DGOB_OK;
+ }
+ else {
+ SOH_DEALLOC(pDiffMB);
+ return DGOB_OK_BUT_BIT_ERROR;
+ }
+
+ headerFailure:
+ SOH_DEALLOC(pDiffMB);
+ sncRewindAndSeekNewMPEGSync(-1, inBuffer, 0, &error);
+ if (error && error != ERR_BIB_NOT_ENOUGH_DATA)
+ return DGOB_ERR;
+ return DGOB_OK_BUT_BIT_ERROR;
+
+ unexpectedError:
+ SOH_DEALLOC(pDiffMB);
+ return DGOB_ERR;
+}
+// End of File