--- encoder.c 2002/10/03 12:06:42 1.76.2.11 +++ encoder.c 2002/12/09 10:47:05 1.76.2.26 @@ -39,7 +39,7 @@ * MinChen * 14.04.2002 added FrameCodeB() * - * $Id: encoder.c,v 1.76.2.11 2002/10/03 12:06:42 suxen_drol Exp $ + * $Id: encoder.c,v 1.76.2.26 2002/12/09 10:47:05 suxen_drol Exp $ * ****************************************************************************/ @@ -54,10 +54,8 @@ #include "global.h" #include "utils/timer.h" #include "image/image.h" -#ifdef BFRAMES #include "image/font.h" #include "motion/sad.h" -#endif #include "motion/motion.h" #include "bitstream/cbp.h" #include "utils/mbfunctions.h" @@ -109,13 +107,6 @@ }; -static void __inline -image_null(IMAGE * image) -{ - image->y = image->u = image->v = NULL; -} - - /***************************************************************************** * Encoder creation * @@ -233,14 +224,14 @@ pEnc->mbParam.m_quant_type = H263_QUANT; - pEnc->sStat.fMvPrevSigma = -1; + pEnc->fMvPrevSigma = -1; /* Fill rate control parameters */ pEnc->bitrate = pParam->rc_bitrate; pEnc->iFrameNum = 0; - pEnc->iMaxKeyInterval = pParam->max_key_interval; + pEnc->mbParam.iMaxKeyInterval = pParam->max_key_interval; /* try to allocate frame memory */ @@ -333,10 +324,11 @@ /* B Frames specific init */ - pEnc->global = pParam->global; + pEnc->mbParam.global = pParam->global; pEnc->mbParam.max_bframes = pParam->max_bframes; - pEnc->bquant_ratio = pParam->bquant_ratio; - pEnc->frame_drop_ratio = pParam->frame_drop_ratio; + pEnc->mbParam.bquant_ratio = pParam->bquant_ratio; + pEnc->mbParam.bquant_offset = pParam->bquant_offset; + pEnc->mbParam.frame_drop_ratio = pParam->frame_drop_ratio; pEnc->bframes = NULL; if (pEnc->mbParam.max_bframes > 0) { @@ -625,7 +617,7 @@ start_timer(); if (image_input (&pEnc->queue[pEnc->queue_tail], pEnc->mbParam.width, pEnc->mbParam.height, - pEnc->mbParam.edged_width, pFrame->image, pFrame->colorspace)) + pEnc->mbParam.edged_width, pFrame->image, pFrame->stride, pFrame->colorspace, pFrame->general & XVID_INTERLACING)) return; stop_conv_timer(); @@ -675,6 +667,7 @@ uint32_t bits, mode; int input_valid = 1; + int bframes_count = 0; #ifdef _DEBUG_PSNR float psnr; @@ -715,11 +708,14 @@ SWAP(pEnc->current, pEnc->bframes[pEnc->bframenum_tail]); FrameCodeP(pEnc, &bs, &bits, 1, 0); + bframes_count = 0; BitstreamPad(&bs); pFrame->length = BitstreamLength(&bs); pFrame->intra = 0; + emms(); + return XVID_ERR_OK; } @@ -733,11 +729,13 @@ BitstreamPad(&bs); pFrame->length = BitstreamLength(&bs); - pFrame->intra = 0; + pFrame->intra = 2; if (input_valid) queue_image(pEnc, pFrame); + emms(); + return XVID_ERR_OK; } @@ -751,7 +749,7 @@ indentical to the future-referece frame. */ - if ((pEnc->global & XVID_GLOBAL_PACKED)) { + if ((pEnc->mbParam.global & XVID_GLOBAL_PACKED)) { int tmp; DPRINTF(DPRINTF_DEBUG,"*** EMPTY bf: head=%i tail=%i queue: head=%i tail=%i size=%i", @@ -766,11 +764,13 @@ pEnc->current->seconds = tmp; pFrame->length = BitstreamLength(&bs); - pFrame->intra = 0; + pFrame->intra = 4; if (input_valid) queue_image(pEnc, pFrame); + emms(); + return XVID_ERR_OK; } } @@ -784,7 +784,7 @@ SWAP(pEnc->current, pEnc->reference); SWAP(pEnc->current, pEnc->bframes[pEnc->bframenum_dx50bvop]); - if ((pEnc->global & XVID_GLOBAL_DEBUG)) { + if ((pEnc->mbParam.global & XVID_GLOBAL_DEBUG)) { image_printf(&pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.height, 5, 100, "DX50 IVOP"); } @@ -801,8 +801,11 @@ start_timer(); if (image_input (&pEnc->current->image, pEnc->mbParam.width, pEnc->mbParam.height, - pEnc->mbParam.edged_width, pFrame->image, pFrame->colorspace)) + pEnc->mbParam.edged_width, pFrame->image, pFrame->stride, pFrame->colorspace, pFrame->general & XVID_INTERLACING)) + { + emms(); return XVID_ERR_FORMAT; + } stop_conv_timer(); // queue input frame, and dequue next image @@ -837,10 +840,11 @@ pEnc->queue_head, pEnc->queue_tail, pEnc->queue_size); BitstreamPutBits(&bs, 0x7f, 8); - pFrame->intra = 0; + pFrame->intra = 5; } pFrame->length = BitstreamLength(&bs); + emms(); return XVID_ERR_OK; } @@ -878,7 +882,7 @@ emms(); - if ((pEnc->global & XVID_GLOBAL_DEBUG)) { + if ((pEnc->mbParam.global & XVID_GLOBAL_DEBUG)) { image_printf(&pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.height, 5, 5, "%i if:%i st:%i", pEnc->m_framenum++, pEnc->iFrameNum, pEnc->current->stamp); } @@ -922,47 +926,62 @@ /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% * ivop/pvop/bvop selection * %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */ - + pEnc->iFrameNum++; if (pEnc->iFrameNum == 0 || pFrame->intra == 1 || pEnc->bframenum_dx50bvop >= 0 || - (pFrame->intra < 0 && pEnc->iMaxKeyInterval > 0 && - pEnc->iFrameNum >= pEnc->iMaxKeyInterval) - || /*image_mad(&pEnc->reference->image, &pEnc->current->image, - pEnc->mbParam.edged_width, pEnc->mbParam.width, - pEnc->mbParam.height) > 30) {*/ - 2 == (mode = MEanalysis(&pEnc->reference->image, &pEnc->current->image, - &pEnc->mbParam, pEnc->current->mbs, pEnc->current->fcode))) { + (pFrame->intra < 0 && pEnc->mbParam.iMaxKeyInterval > 0 && + pEnc->iFrameNum >= pEnc->mbParam.iMaxKeyInterval) + || 2 == (mode = MEanalysis(&pEnc->reference->image, pEnc->current, + &pEnc->mbParam, pEnc->mbParam.iMaxKeyInterval, + (pFrame->intra < 0) ? pEnc->iFrameNum : 0, + bframes_count++))) { /* * This will be coded as an Intra Frame */ + if ((pEnc->current->global_flags & XVID_QUARTERPEL)) + pEnc->mbParam.m_quarterpel = 1; + else + pEnc->mbParam.m_quarterpel = 0; + + if (pEnc->current->global_flags & XVID_MPEGQUANT) pEnc->mbParam.m_quant_type = MPEG4_QUANT; + + if ((pEnc->current->global_flags & XVID_CUSTOM_QMATRIX) > 0) { + if (pFrame->quant_intra_matrix != NULL) + set_intra_matrix(pFrame->quant_intra_matrix); + if (pFrame->quant_inter_matrix != NULL) + set_inter_matrix(pFrame->quant_inter_matrix); + } + DPRINTF(DPRINTF_DEBUG,"*** IFRAME bf: head=%i tail=%i queue: head=%i tail=%i size=%i", pEnc->bframenum_head, pEnc->bframenum_tail, pEnc->queue_head, pEnc->queue_tail, pEnc->queue_size); - if ((pEnc->global & XVID_GLOBAL_DEBUG)) { + if ((pEnc->mbParam.global & XVID_GLOBAL_DEBUG)) { image_printf(&pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.height, 5, 200, "IVOP"); } // when we reach an iframe in DX50BVOP mode, encode the last bframe as a pframe - if ((pEnc->global & XVID_GLOBAL_DX50BVOP) && pEnc->bframenum_tail > 0) { + if ((pEnc->mbParam.global & XVID_GLOBAL_DX50BVOP) && pEnc->bframenum_tail > 0) { pEnc->bframenum_tail--; pEnc->bframenum_dx50bvop = pEnc->bframenum_tail; SWAP(pEnc->current, pEnc->bframes[pEnc->bframenum_dx50bvop]); - if ((pEnc->global & XVID_GLOBAL_DEBUG)) { + if ((pEnc->mbParam.global & XVID_GLOBAL_DEBUG)) { image_printf(&pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.height, 5, 100, "DX50 BVOP->PVOP"); } FrameCodeP(pEnc, &bs, &bits, 1, 0); + bframes_count = 0; pFrame->intra = 0; } else { FrameCodeI(pEnc, &bs, &bits); + bframes_count = 0; pFrame->intra = 1; pEnc->bframenum_dx50bvop = -1; @@ -970,7 +989,7 @@ pEnc->flush_bframes = 1; - if ((pEnc->global & XVID_GLOBAL_PACKED) && pEnc->bframenum_tail > 0) { + if ((pEnc->mbParam.global & XVID_GLOBAL_PACKED) && pEnc->bframenum_tail > 0) { BitstreamPadAlways(&bs); input_valid = 0; goto ipvop_loop; @@ -981,6 +1000,7 @@ * go screwy with divx 5.00 */ } else if (pEnc->bframenum_tail >= pEnc->mbParam.max_bframes || mode != 0) { +// } else if (pFrame->intra == 0 || pEnc->bframenum_tail >= pEnc->mbParam.max_bframes || mode != 0) { /* * This will be coded as a Predicted Frame */ @@ -989,15 +1009,16 @@ pEnc->bframenum_head, pEnc->bframenum_tail, pEnc->queue_head, pEnc->queue_tail, pEnc->queue_size); - if ((pEnc->global & XVID_GLOBAL_DEBUG)) { + if ((pEnc->mbParam.global & XVID_GLOBAL_DEBUG)) { image_printf(&pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.height, 5, 200, "PVOP"); } FrameCodeP(pEnc, &bs, &bits, 1, 0); + bframes_count = 0; pFrame->intra = 0; pEnc->flush_bframes = 1; - if ((pEnc->global & XVID_GLOBAL_PACKED)) { + if ((pEnc->mbParam.global & XVID_GLOBAL_PACKED) && (pEnc->bframenum_tail > 0)) { BitstreamPadAlways(&bs); input_valid = 0; goto ipvop_loop; @@ -1008,29 +1029,26 @@ * This will be coded as a Bidirectional Frame */ - if ((pEnc->global & XVID_GLOBAL_DEBUG)) { + if ((pEnc->mbParam.global & XVID_GLOBAL_DEBUG)) { image_printf(&pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.height, 5, 200, "BVOP"); } if (pFrame->bquant < 1) { - pEnc->current->quant = - ((pEnc->reference->quant + - pEnc->current->quant) * pEnc->bquant_ratio) / 200; + pEnc->current->quant = ((((pEnc->reference->quant + pEnc->current->quant) * + pEnc->mbParam.bquant_ratio) / 2) + pEnc->mbParam.bquant_offset)/100; + } else { pEnc->current->quant = pFrame->bquant; } - if (pEnc->current->quant < 1) - pEnc->current->quant = 1; - if (pEnc->current->quant > 31) - pEnc->current->quant = 31; + if (pEnc->current->quant < 1) + pEnc->current->quant = 1; + else if (pEnc->current->quant > 31) + pEnc->current->quant = 31; - - DPRINTF(DPRINTF_DEBUG,"*** BFRAME (store) bf: head=%i tail=%i queue: head=%i tail=%i size=%i quant=%i\n", - pEnc->bframenum_head, pEnc->bframenum_tail, - pEnc->queue_head, pEnc->queue_tail, pEnc->queue_size,pEnc->current->quant); - - + DPRINTF(DPRINTF_DEBUG,"*** BFRAME (store) bf: head=%i tail=%i queue: head=%i tail=%i size=%i quant=%i\n", + pEnc->bframenum_head, pEnc->bframenum_tail, + pEnc->queue_head, pEnc->queue_tail, pEnc->queue_size,pEnc->current->quant); /* store frame into bframe buffer & swap ref back to current */ SWAP(pEnc->current, pEnc->bframes[pEnc->bframenum_tail]); @@ -1038,24 +1056,23 @@ pEnc->bframenum_tail++; - pFrame->intra = 0; +// bframe report by koepi + pFrame->intra = 2; pFrame->length = 0; input_valid = 0; goto bvop_loop; } - pEnc->iFrameNum++; - BitstreamPad(&bs); pFrame->length = BitstreamLength(&bs); if (pResult) { pResult->quant = pEnc->current->quant; - pResult->hlength = pFrame->length - (pEnc->sStat.iTextBits / 8); - pResult->kblks = pEnc->sStat.kblks; - pResult->mblks = pEnc->sStat.mblks; - pResult->ublks = pEnc->sStat.ublks; + pResult->hlength = pFrame->length - (pEnc->current->sStat.iTextBits / 8); + pResult->kblks = pEnc->current->sStat.kblks; + pResult->mblks = pEnc->current->sStat.mblks; + pResult->ublks = pEnc->current->sStat.ublks; } emms(); @@ -1078,6 +1095,7 @@ stop_global_timer(); write_timer(); + emms(); return XVID_ERR_OK; } @@ -1132,7 +1150,7 @@ start_timer(); if (image_input (&pEnc->current->image, pEnc->mbParam.width, pEnc->mbParam.height, - pEnc->mbParam.edged_width, pFrame->image, pFrame->colorspace) < 0) + pEnc->mbParam.edged_width, pFrame->image, pFrame->stride, pFrame->colorspace, pFrame->general & XVID_INTERLACING) < 0) return XVID_ERR_FORMAT; stop_conv_timer(); @@ -1151,6 +1169,11 @@ pEnc->current->quant = pFrame->quant; } + if ((pEnc->current->global_flags & XVID_QUARTERPEL)) + pEnc->mbParam.m_quarterpel = 1; + else + pEnc->mbParam.m_quarterpel = 0; + if ((pEnc->current->global_flags & XVID_LUMIMASKING)) { int *temp_dquants = (int *) xvid_malloc(pEnc->mbParam.mb_width * @@ -1212,8 +1235,8 @@ if (pFrame->intra < 0) { if ((pEnc->iFrameNum == 0) - || ((pEnc->iMaxKeyInterval > 0) - && (pEnc->iFrameNum >= pEnc->iMaxKeyInterval))) { + || ((pEnc->mbParam.iMaxKeyInterval > 0) + && (pEnc->iFrameNum >= pEnc->mbParam.iMaxKeyInterval))) { pFrame->intra = FrameCodeI(pEnc, &bs, &bits); } else { pFrame->intra = FrameCodeP(pEnc, &bs, &bits, 0, write_vol_header); @@ -1234,10 +1257,10 @@ if (pResult) { pResult->quant = pEnc->current->quant; - pResult->hlength = pFrame->length - (pEnc->sStat.iTextBits / 8); - pResult->kblks = pEnc->sStat.kblks; - pResult->mblks = pEnc->sStat.mblks; - pResult->ublks = pEnc->sStat.ublks; + pResult->hlength = pFrame->length - (pEnc->current->sStat.iTextBits / 8); + pResult->kblks = pEnc->current->sStat.kblks; + pResult->mblks = pEnc->current->sStat.mblks; + pResult->ublks = pEnc->current->sStat.ublks; } emms(); @@ -1495,35 +1518,56 @@ Bitstream * bs, uint32_t * pBits) { + int mb_width = pEnc->mbParam.mb_width; + int mb_height = pEnc->mbParam.mb_height; DECLARE_ALIGNED_MATRIX(dct_codes, 6, 64, int16_t, CACHE_LINE); DECLARE_ALIGNED_MATRIX(qcoeff, 6, 64, int16_t, CACHE_LINE); uint16_t x, y; + if ((pEnc->current->global_flags & XVID_REDUCED)) + { + mb_width = (pEnc->mbParam.width + 31) / 32; + mb_height = (pEnc->mbParam.height + 31) / 32; + + /* 16x16->8x8 downsample requires 1 additional edge pixel*/ + /* XXX: setedges is overkill */ + start_timer(); + image_setedges(&pEnc->current->image, + pEnc->mbParam.edged_width, pEnc->mbParam.edged_height, + pEnc->mbParam.width, pEnc->mbParam.height); + stop_edges_timer(); + } + pEnc->iFrameNum = 0; pEnc->mbParam.m_rounding_type = 1; pEnc->current->rounding_type = pEnc->mbParam.m_rounding_type; + pEnc->current->quarterpel = pEnc->mbParam.m_quarterpel; pEnc->current->coding_type = I_VOP; BitstreamWriteVolHeader(bs, &pEnc->mbParam, pEnc->current); + /* XXX: move this stuff to BitstreamWriteVolHeader */ #define DIVX501B481P "DivX501b481p" - if ((pEnc->global & XVID_GLOBAL_PACKED)) { + if ((pEnc->mbParam.global & XVID_GLOBAL_PACKED)) { BitstreamWriteUserData(bs, DIVX501B481P, strlen(DIVX501B481P)); } - + +#define XVID_ID "XviD" XVID_BS_VERSION + BitstreamWriteUserData(bs, XVID_ID, strlen(XVID_ID)); + set_timecodes(pEnc->current,pEnc->reference,pEnc->mbParam.fbase); BitstreamWriteVopHeader(bs, &pEnc->mbParam, pEnc->current, 1); *pBits = BitstreamPos(bs); - pEnc->sStat.iTextBits = 0; - pEnc->sStat.kblks = pEnc->mbParam.mb_width * pEnc->mbParam.mb_height; - pEnc->sStat.mblks = pEnc->sStat.ublks = 0; + pEnc->current->sStat.iTextBits = 0; + pEnc->current->sStat.kblks = mb_width * mb_height; + pEnc->current->sStat.mblks = pEnc->current->sStat.ublks = 0; - for (y = 0; y < pEnc->mbParam.mb_height; y++) - for (x = 0; x < pEnc->mbParam.mb_width; x++) { + for (y = 0; y < mb_height; y++) + for (x = 0; x < mb_width; x++) { MACROBLOCK *pMB = &pEnc->current->mbs[x + y * pEnc->mbParam.mb_width]; @@ -1542,16 +1586,14 @@ qcoeff[4*64+0]=0; /* zero, because for INTRA MBs DC value is saved */ qcoeff[5*64+0]=0; } - MBCoding(pEnc->current, pMB, qcoeff, bs, &pEnc->sStat); + MBCoding(pEnc->current, pMB, qcoeff, bs, &pEnc->current->sStat); stop_coding_timer(); } emms(); *pBits = BitstreamPos(bs) - *pBits; - pEnc->sStat.fMvPrevSigma = -1; - pEnc->sStat.iMvSum = 0; - pEnc->sStat.iMvCount = 0; + pEnc->fMvPrevSigma = -1; pEnc->mbParam.m_fcode = 2; if (pEnc->current->global_flags & XVID_HINTEDME_GET) { @@ -1577,14 +1619,27 @@ DECLARE_ALIGNED_MATRIX(dct_codes, 6, 64, int16_t, CACHE_LINE); DECLARE_ALIGNED_MATRIX(qcoeff, 6, 64, int16_t, CACHE_LINE); + int mb_width = pEnc->mbParam.mb_width; + int mb_height = pEnc->mbParam.mb_height; + int iLimit; int x, y, k; int iSearchRange; - int bIntra; + int bIntra, skip_possible; /* IMAGE *pCurrent = &pEnc->current->image; */ IMAGE *pRef = &pEnc->reference->image; + if ((pEnc->current->global_flags & XVID_REDUCED)) + { + // mb_width = (pEnc->mbParam.width + 31) / 32; + // mb_height = (pEnc->mbParam.height + 31) / 32; + + /* XXX: reduced resoltion not yet supported */ + pEnc->current->global_flags &= ~XVID_REDUCED; + } + + start_timer(); image_setedges(pRef, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height, pEnc->mbParam.width, pEnc->mbParam.height); @@ -1592,24 +1647,31 @@ pEnc->mbParam.m_rounding_type = 1 - pEnc->mbParam.m_rounding_type; pEnc->current->rounding_type = pEnc->mbParam.m_rounding_type; + pEnc->current->quarterpel = pEnc->mbParam.m_quarterpel; pEnc->current->fcode = pEnc->mbParam.m_fcode; if (!force_inter) - iLimit = - (int) (pEnc->mbParam.mb_width * pEnc->mbParam.mb_height * - INTRA_THRESHOLD); + iLimit = (int)(mb_width * mb_height * INTRA_THRESHOLD); else - iLimit = pEnc->mbParam.mb_width * pEnc->mbParam.mb_height + 1; + iLimit = mb_width * mb_height + 1; if ((pEnc->current->global_flags & XVID_HALFPEL)) { start_timer(); image_interpolate(pRef, &pEnc->vInterH, &pEnc->vInterV, &pEnc->vInterHV, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height, + pEnc->mbParam.m_quarterpel, pEnc->current->rounding_type); stop_inter_timer(); } + if (pEnc->current->global_flags & XVID_GMC) { +// printf("Global Motion = %d %d quarterpel=%d\n", pEnc->current->GMC_MV.x, pEnc->current->GMC_MV.y,pEnc->current->quarterpel); + DPRINTF(DPRINTF_HEADER, "Global Motion = %d %d quarterpel=%d\n", pEnc->current->GMC_MV.x, pEnc->current->GMC_MV.y,pEnc->current->quarterpel); + pEnc->current->coding_type = S_VOP; + } else + pEnc->current->coding_type = P_VOP; + start_timer(); if (pEnc->current->global_flags & XVID_HINTEDME_SET) { HintedMESet(pEnc, &bIntra); @@ -1621,17 +1683,18 @@ } else { - bIntra = - MotionEstimation(&pEnc->mbParam, pEnc->current, pEnc->reference, + bIntra = + MotionEstimation(&pEnc->mbParam, pEnc->current, pEnc->reference, &pEnc->vInterH, &pEnc->vInterV, &pEnc->vInterHV, iLimit); - } stop_motion_timer(); if (bIntra == 1) return FrameCodeI(pEnc, bs, pBits); - pEnc->current->coding_type = P_VOP; + if ( (pEnc->current->GMC_MV.x == 0) && (pEnc->current->GMC_MV.y == 0) ) + pEnc->current->coding_type = P_VOP; /* no global motion -> no GMC */ + if (vol_header) BitstreamWriteVolHeader(bs, &pEnc->mbParam, pEnc->current); @@ -1642,11 +1705,11 @@ *pBits = BitstreamPos(bs); - pEnc->sStat.iTextBits = pEnc->sStat.iMvSum = pEnc->sStat.iMvCount = - pEnc->sStat.kblks = pEnc->sStat.mblks = pEnc->sStat.ublks = 0; + pEnc->current->sStat.iTextBits = pEnc->current->sStat.iMvSum = pEnc->current->sStat.iMvCount = + pEnc->current->sStat.kblks = pEnc->current->sStat.mblks = pEnc->current->sStat.ublks = 0; - for (y = 0; y < pEnc->mbParam.mb_height; y++) { - for (x = 0; x < pEnc->mbParam.mb_width; x++) { + for (y = 0; y < mb_height; y++) { + for (x = 0; x < mb_width; x++) { MACROBLOCK *pMB = &pEnc->current->mbs[x + y * pEnc->mbParam.mb_width]; @@ -1660,6 +1723,8 @@ dct_codes, pEnc->mbParam.width, pEnc->mbParam.height, pEnc->mbParam.edged_width, + pEnc->mbParam.m_quarterpel, + (pEnc->current->global_flags & XVID_REDUCED), pEnc->current->rounding_type); stop_comp_timer(); @@ -1692,49 +1757,69 @@ stop_prediction_timer(); if (pMB->mode == MODE_INTRA || pMB->mode == MODE_INTRA_Q) { - pEnc->sStat.kblks++; + pEnc->current->sStat.kblks++; } else if (pMB->cbp || pMB->mvs[0].x || pMB->mvs[0].y || pMB->mvs[1].x || pMB->mvs[1].y || pMB->mvs[2].x || pMB->mvs[2].y || pMB->mvs[3].x || pMB->mvs[3].y) { - pEnc->sStat.mblks++; + pEnc->current->sStat.mblks++; } else { - pEnc->sStat.ublks++; + pEnc->current->sStat.ublks++; } start_timer(); /* Finished processing the MB, now check if to CODE or SKIP */ - if ((pMB->mode == MODE_NOT_CODED) || - (pMB->cbp == 0 && pMB->mode == MODE_INTER && pMB->mvs[0].x == 0 && - pMB->mvs[0].y == 0 && pMB->dquant == NO_CHANGE)) { - -/* This is a candidate for SKIPping, but check intermediate B-frames first */ - - int bSkip = 1; - pMB->mode = MODE_NOT_CODED; - - for (k=pEnc->bframenum_head; k< pEnc->bframenum_tail; k++) - { - int iSAD; - iSAD = sad16(pEnc->reference->image.y + 16*y*pEnc->mbParam.edged_width + 16*x, - pEnc->bframes[k]->image.y + 16*y*pEnc->mbParam.edged_width + 16*x, + skip_possible = (pMB->cbp == 0) & (pMB->mode == MODE_INTER) & + (pMB->dquant == NO_CHANGE); + + if(pEnc->mbParam.m_quarterpel) + { skip_possible &= (pMB->qmvs[0].x == pEnc->current->GMC_MV.x) & (pMB->qmvs[0].y == pEnc->current->GMC_MV.y); + } + else + { skip_possible &= (pMB->mvs[0].x == pEnc->current->GMC_MV.x) & (pMB->mvs[0].y == pEnc->current->GMC_MV.y); + } + + if ( (pMB->mode == MODE_NOT_CODED) || (skip_possible)) { + +/* This is a candidate for SKIPping, but for P-VOPs check intermediate B-frames first */ + int bSkip = 1; + + if (pEnc->current->coding_type == P_VOP) /* special rule for P-VOP's SKIP */ + for (k=pEnc->bframenum_head; k< pEnc->bframenum_tail; k++) + { + int iSAD; + iSAD = sad16(pEnc->reference->image.y + 16*y*pEnc->mbParam.edged_width + 16*x, + pEnc->bframes[k]->image.y + 16*y*pEnc->mbParam.edged_width + 16*x, pEnc->mbParam.edged_width,BFRAME_SKIP_THRESHHOLD); - if (iSAD >= BFRAME_SKIP_THRESHHOLD * pMB->quant) - { bSkip = 0; - break; + if (iSAD >= BFRAME_SKIP_THRESHHOLD * pMB->quant) + { bSkip = 0; + break; + } } - } - if (!bSkip) - { + + if (!bSkip) + { VECTOR predMV; - predMV = get_pmv2(pEnc->current->mbs, pEnc->mbParam.mb_width, 0, x, y, 0); - pMB->pmvs[0].x = -predMV.x; pMB->pmvs[0].y = -predMV.y; + if(pEnc->mbParam.m_quarterpel) { + predMV = get_qpmv2(pEnc->current->mbs, pEnc->mbParam.mb_width, 0, x, y, 0); + pMB->pmvs[0].x = pMB->qmvs[0].x - predMV.x; /* with GMC, qmvs doesn't have to be (0,0)! */ + pMB->pmvs[0].y = pMB->qmvs[0].y - predMV.y; + } + else { + predMV = get_pmv2(pEnc->current->mbs, pEnc->mbParam.mb_width, 0, x, y, 0); + pMB->pmvs[0].x = pMB->mvs[0].x - predMV.x; /* with GMC, mvs doesn't have to be (0,0)! */ + pMB->pmvs[0].y = pMB->mvs[0].y - predMV.y; + } pMB->mode = MODE_INTER; pMB->cbp = 0; - MBCoding(pEnc->current, pMB, qcoeff, bs, &pEnc->sStat); + MBCoding(pEnc->current, pMB, qcoeff, bs, &pEnc->current->sStat); + } + else + { + pMB->mode = MODE_NOT_CODED; + MBSkip(bs); } - else MBSkip(bs); } else { if (pEnc->current->global_flags & XVID_GREYSCALE) @@ -1742,7 +1827,7 @@ qcoeff[4*64+0]=0; /* zero, because DC for INTRA MBs DC value is saved */ qcoeff[5*64+0]=0; } - MBCoding(pEnc->current, pMB, qcoeff, bs, &pEnc->sStat); + MBCoding(pEnc->current, pMB, qcoeff, bs, &pEnc->current->sStat); } stop_coding_timer(); @@ -1755,37 +1840,36 @@ HintedMEGet(pEnc, 0); } - if (pEnc->sStat.iMvCount == 0) - pEnc->sStat.iMvCount = 1; + if (pEnc->current->sStat.iMvCount == 0) + pEnc->current->sStat.iMvCount = 1; - fSigma = (float) sqrt((float) pEnc->sStat.iMvSum / pEnc->sStat.iMvCount); + fSigma = (float) sqrt((float) pEnc->current->sStat.iMvSum / pEnc->current->sStat.iMvCount); iSearchRange = 1 << (3 + pEnc->mbParam.m_fcode); if ((fSigma > iSearchRange / 3) - && (pEnc->mbParam.m_fcode <= 3)) // maximum search range 128 + && (pEnc->mbParam.m_fcode <= (3 + pEnc->mbParam.m_quarterpel))) // maximum search range 128 { pEnc->mbParam.m_fcode++; iSearchRange *= 2; } else if ((fSigma < iSearchRange / 6) - && (pEnc->sStat.fMvPrevSigma >= 0) - && (pEnc->sStat.fMvPrevSigma < iSearchRange / 6) - && (pEnc->mbParam.m_fcode >= 2)) // minimum search range 16 + && (pEnc->fMvPrevSigma >= 0) + && (pEnc->fMvPrevSigma < iSearchRange / 6) + && (pEnc->mbParam.m_fcode >= (2 + pEnc->mbParam.m_quarterpel))) // minimum search range 16 { pEnc->mbParam.m_fcode--; iSearchRange /= 2; } - pEnc->sStat.fMvPrevSigma = fSigma; + pEnc->fMvPrevSigma = fSigma; -#ifdef FRAMEDROP /* frame drop code */ - // DPRINTF(DPRINTF_DEBUG, "kmu %i %i %i", pEnc->sStat.kblks, pEnc->sStat.mblks, pEnc->sStat.ublks); - if (pEnc->sStat.kblks + pEnc->sStat.mblks < - (pEnc->frame_drop_ratio * pEnc->mbParam.mb_width * pEnc->mbParam.mb_height) / 100) + // DPRINTF(DPRINTF_DEBUG, "kmu %i %i %i", pEnc->current->sStat.kblks, pEnc->current->sStat.mblks, pEnc->current->sStat.ublks); + if (pEnc->current->sStat.kblks + pEnc->current->sStat.mblks < + (pEnc->mbParam.frame_drop_ratio * mb_width * mb_height) / 100) { - pEnc->sStat.kblks = pEnc->sStat.mblks = 0; - pEnc->sStat.ublks = pEnc->mbParam.mb_width * pEnc->mbParam.mb_height; + pEnc->current->sStat.kblks = pEnc->current->sStat.mblks = 0; + pEnc->current->sStat.ublks = mb_width * mb_height; BitstreamReset(bs); @@ -1796,13 +1880,27 @@ pEnc->current->quant = pEnc->reference->quant; pEnc->current->motion_flags = pEnc->reference->motion_flags; pEnc->current->rounding_type = pEnc->reference->rounding_type; + pEnc->current->quarterpel = pEnc->reference->quarterpel; pEnc->current->fcode = pEnc->reference->fcode; pEnc->current->bcode = pEnc->reference->bcode; image_copy(&pEnc->current->image, &pEnc->reference->image, pEnc->mbParam.edged_width, pEnc->mbParam.height); - memcpy(pEnc->current->mbs, pEnc->reference->mbs, sizeof(MACROBLOCK) * pEnc->mbParam.mb_width * pEnc->mbParam.mb_height); + memcpy(pEnc->current->mbs, pEnc->reference->mbs, sizeof(MACROBLOCK) * mb_width * mb_height); + } + /* XXX: debug + { + char s[100]; + sprintf(s, "\\%05i_cur.pgm", pEnc->m_framenum); + image_dump_yuvpgm(&pEnc->current->image, + pEnc->mbParam.edged_width, + pEnc->mbParam.width, pEnc->mbParam.height, s); + + sprintf(s, "\\%05i_ref.pgm", pEnc->m_framenum); + image_dump_yuvpgm(&pEnc->reference->image, + pEnc->mbParam.edged_width, + pEnc->mbParam.width, pEnc->mbParam.height, s); } -#endif + */ *pBits = BitstreamPos(bs) - *pBits; @@ -1810,7 +1908,7 @@ } -static __inline void +static void FrameCodeB(Encoder * pEnc, FRAMEINFO * frame, Bitstream * bs, @@ -1830,11 +1928,15 @@ fprintf(fp,"Y=%3d X=%3d MB=%2d CBP=%02X\n",y,x,mb->mode,mb->cbp); \ } + pEnc->current->global_flags &= ~XVID_REDUCED; /* reduced resoltion not yet supported */ + if (!first){ fp=fopen("C:\\XVIDDBGE.TXT","w"); } #endif + frame->quarterpel = pEnc->mbParam.m_quarterpel; + // forward image_setedges(f_ref, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height, pEnc->mbParam.width, @@ -1842,7 +1944,7 @@ start_timer(); image_interpolate(f_ref, &pEnc->f_refh, &pEnc->f_refv, &pEnc->f_refhv, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height, - 0); + pEnc->mbParam.m_quarterpel, 0); stop_inter_timer(); // backward @@ -1852,7 +1954,7 @@ start_timer(); image_interpolate(b_ref, &pEnc->vInterH, &pEnc->vInterV, &pEnc->vInterHV, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height, - 0); + pEnc->mbParam.m_quarterpel, 0); stop_inter_timer(); start_timer(); @@ -1862,7 +1964,7 @@ ((int32_t)(pEnc->current->stamp - pEnc->reference->stamp)), // time_pp pEnc->reference->mbs, f_ref, &pEnc->f_refh, &pEnc->f_refv, &pEnc->f_refhv, - pEnc->current->mbs, b_ref, &pEnc->vInterH, + pEnc->current, b_ref, &pEnc->vInterH, &pEnc->vInterV, &pEnc->vInterHV); @@ -1880,16 +1982,16 @@ *pBits = BitstreamPos(bs); - pEnc->sStat.iTextBits = 0; - pEnc->sStat.iMvSum = 0; - pEnc->sStat.iMvCount = 0; - pEnc->sStat.kblks = pEnc->sStat.mblks = pEnc->sStat.ublks = 0; + frame->sStat.iTextBits = 0; + frame->sStat.iMvSum = 0; + frame->sStat.iMvCount = 0; + frame->sStat.kblks = frame->sStat.mblks = frame->sStat.ublks = 0; for (y = 0; y < pEnc->mbParam.mb_height; y++) { for (x = 0; x < pEnc->mbParam.mb_width; x++) { MACROBLOCK * const mb = &frame->mbs[x + y * pEnc->mbParam.mb_width]; - int direction = pEnc->global & XVID_ALTERNATESCAN ? 2 : 0; + int direction = pEnc->mbParam.global & XVID_ALTERNATESCAN ? 2 : 0; // decoder ignores mb when refence block is INTER(0,0), CBP=0 if (mb->mode == MODE_NOT_CODED) { @@ -1921,7 +2023,7 @@ #endif start_timer(); MBCodingBVOP(mb, qcoeff, frame->fcode, frame->bcode, bs, - &pEnc->sStat, direction); + &frame->sStat, direction); stop_coding_timer(); } }