--- trunk/xvidcore/src/encoder.c 2004/04/04 11:47:21 1406 +++ trunk/xvidcore/src/encoder.c 2005/05/23 09:29:43 1617 @@ -21,7 +21,7 @@ * along with this program ; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: encoder.c,v 1.105 2004-04-04 11:47:21 syskin Exp $ + * $Id: encoder.c,v 1.118 2005-05-23 09:29:43 Skal Exp $ * ****************************************************************************/ @@ -85,26 +85,48 @@ /* * Simplify the "fincr/fbase" fraction */ +static int +gcd(int a, int b) +{ + int r ; + + if (b > a) { + r = a; + a = b; + b = r; + } + + while ((r = a % b)) { + a = b; + b = r; + } + return b; +} + static void simplify_time(int *inc, int *base) { /* common factor */ - int i = *inc; - while (i > 1) { - if (*inc % i == 0 && *base % i == 0) { - *inc /= i; - *base /= i; - i = *inc; - continue; - } - i--; - } - - /* if neccessary, round to 65535 accuracy */ - if (*base > 65535) { - float div = (float) *base / 65535; - *base = (int) (*base / div); - *inc = (int) (*inc / div); + const int s = gcd(*inc, *base); + *inc /= s; + *base /= s; + + if (*base > 65535 || *inc > 65535) { + int *biggest; + int *other; + float div; + + if (*base > *inc) { + biggest = base; + other = inc; + } else { + biggest = inc; + other = base; + } + + div = ((float)*biggest)/((float)65535); + *biggest = (unsigned int)(((float)*biggest)/div); + *other = (unsigned int)(((float)*other)/div); } } @@ -135,6 +157,8 @@ /* global flags */ pEnc->mbParam.global_flags = create->global; + if ((pEnc->mbParam.global_flags & XVID_GLOBAL_PACKED)) + pEnc->mbParam.global_flags |= XVID_GLOBAL_DIVX5_USERDATA; /* width, height */ pEnc->mbParam.width = create->width; @@ -148,8 +172,8 @@ pEnc->mbParam.fincr = MAX(create->fincr, 0); pEnc->mbParam.fbase = create->fincr <= 0 ? 25 : create->fbase; if (pEnc->mbParam.fincr>0) - simplify_time(&pEnc->mbParam.fincr, &pEnc->mbParam.fbase); - + simplify_time((int*)&pEnc->mbParam.fincr, (int*)&pEnc->mbParam.fbase); + /* zones */ if(create->num_zones > 0) { pEnc->num_zones = create->num_zones; @@ -861,24 +885,6 @@ #endif } -static int -gcd(int a, int b) -{ - int r ; - - if (b > a) { - r = a; - a = b; - b = r; - } - - while ((r = a % b)) { - a = b; - b = r; - } - return b; -} - static void simplify_par(int *par_width, int *par_height) { @@ -1142,7 +1148,7 @@ type = frame->type; pEnc->current->quant = frame->quant; - call_plugins(pEnc, pEnc->current, NULL, XVID_PLG_BEFORE, &type, &pEnc->current->quant, stats); + call_plugins(pEnc, pEnc->current, NULL, XVID_PLG_BEFORE, &type, (int*)&pEnc->current->quant, stats); if (type > 0){ /* XVID_TYPE_?VOP */ type = type2coding(type); /* convert XVID_TYPE_?VOP to bitstream coding type */ @@ -1245,7 +1251,7 @@ SWAP(FRAMEINFO*, pEnc->current, pEnc->bframes[pEnc->bframenum_tail]); if ((pEnc->current->vop_flags & XVID_VOP_DEBUG)) { - image_printf(&pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.height, 5, 100, "DX50 BVOP->PVOP"); + image_printf(&pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.height, 5, 100, "CLOSED GOP BVOP->PVOP"); } /* convert B-VOP quant to P-VOP */ @@ -1306,9 +1312,6 @@ /* prevent vol/vop misuse */ - if (!(pEnc->current->vol_flags & XVID_VOL_REDUCED_ENABLE)) - pEnc->current->vop_flags &= ~XVID_VOP_REDUCED; - if (!(pEnc->current->vol_flags & XVID_VOL_INTERLACING)) pEnc->current->vop_flags &= ~(XVID_VOP_TOPFIELDFIRST|XVID_VOP_ALTERNATESCAN); @@ -1436,20 +1439,6 @@ uint16_t x, y; - if ((pEnc->current->vol_flags & XVID_VOL_REDUCED_ENABLE)) - { - 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, 0); - stop_edges_timer(); - } - pEnc->mbParam.m_rounding_type = 1; pEnc->current->rounding_type = pEnc->mbParam.m_rounding_type; pEnc->current->coding_type = I_VOP; @@ -1485,21 +1474,10 @@ stop_prediction_timer(); start_timer(); - if (pEnc->current->vop_flags & XVID_VOP_GREYSCALE) - { pMB->cbp &= 0x3C; /* keep only bits 5-2 */ - 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->current->sStat); stop_coding_timer(); } - if ((pEnc->current->vop_flags & XVID_VOP_REDUCED)) - { - image_deblock_rrv(&pEnc->current->image, pEnc->mbParam.edged_width, - pEnc->current->mbs, mb_width, mb_height, pEnc->mbParam.mb_width, - 16, 0); - } emms(); BitstreamPadAlways(bs); /* next_start_code() at the end of VideoObjectPlane() */ @@ -1515,25 +1493,43 @@ return 1; /* intra */ } +static __inline void +updateFcode(Statistics * sStat, Encoder * pEnc) +{ + float fSigma; + int iSearchRange; -#define INTRA_THRESHOLD 0.5 -#define BFRAME_SKIP_THRESHHOLD 30 + if (sStat->iMvCount == 0) + sStat->iMvCount = 1; + + fSigma = (float) sqrt((float) sStat->iMvSum / sStat->iMvCount); + + iSearchRange = 16 << pEnc->mbParam.m_fcode; + + if ((3.0 * fSigma > iSearchRange) && (pEnc->mbParam.m_fcode <= 5) ) + pEnc->mbParam.m_fcode++; + + else if ((5.0 * fSigma < iSearchRange) + && (4.0 * pEnc->fMvPrevSigma < iSearchRange) + && (pEnc->mbParam.m_fcode >= 2) ) + pEnc->mbParam.m_fcode--; + pEnc->fMvPrevSigma = fSigma; +} + +#define BFRAME_SKIP_THRESHHOLD 30 /* FrameCodeP also handles S(GMC)-VOPs */ static int FrameCodeP(Encoder * pEnc, Bitstream * bs) { - float fSigma; int bits = BitstreamPos(bs); DECLARE_ALIGNED_MATRIX(dct_codes, 6, 64, int16_t, CACHE_LINE); DECLARE_ALIGNED_MATRIX(qcoeff, 6, 64, int16_t, CACHE_LINE); int x, y, k; - int iSearchRange; - int skip_possible; FRAMEINFO *const current = pEnc->current; FRAMEINFO *const reference = pEnc->reference; MBParam * const pParam = &pEnc->mbParam; @@ -1541,17 +1537,8 @@ int mb_height = pParam->mb_height; int coded = 1; - - /* IMAGE *pCurrent = ¤t->image; */ IMAGE *pRef = &reference->image; - if ((current->vop_flags & XVID_VOP_REDUCED)) - { - mb_width = (pParam->width + 31) / 32; - mb_height = (pParam->height + 31) / 32; - } - - if (!reference->is_edged) { start_timer(); image_setedges(pRef, pParam->edged_width, pParam->edged_height, @@ -1577,6 +1564,9 @@ } } + current->sStat.iTextBits = current->sStat.iMvSum = current->sStat.iMvCount = + current->sStat.kblks = current->sStat.mblks = current->sStat.ublks = 0; + current->coding_type = P_VOP; call_plugins(pEnc, pEnc->current, NULL, XVID_PLG_FRAME, NULL, NULL, NULL); @@ -1645,18 +1635,12 @@ BitstreamWriteVopHeader(bs, &pEnc->mbParam, current, 1, current->mbs[0].quant); - current->sStat.iTextBits = current->sStat.iMvSum = current->sStat.iMvCount = - current->sStat.kblks = current->sStat.mblks = current->sStat.ublks = 0; - - for (y = 0; y < mb_height; y++) { for (x = 0; x < mb_width; x++) { - MACROBLOCK *pMB = - ¤t->mbs[x + y * pParam->mb_width]; + MACROBLOCK *pMB = ¤t->mbs[x + y * pParam->mb_width]; + int skip_possible; - int bIntra = (pMB->mode == MODE_INTRA) || (pMB->mode == MODE_INTRA_Q); - - if (bIntra) { + if (pMB->mode == MODE_INTRA || pMB->mode == MODE_INTRA_Q) { CodeIntraMB(pEnc, pMB); MBTransQuantIntra(&pEnc->mbParam, current, pMB, x, y, dct_codes, qcoeff); @@ -1667,11 +1651,6 @@ current->sStat.kblks++; - if (pEnc->current->vop_flags & XVID_VOP_GREYSCALE) - { pMB->cbp &= 0x3C; /* keep only bits 5-2 */ - qcoeff[4*64+0]=0; /* zero, because for INTRA MBs DC value is saved */ - qcoeff[5*64+0]=0; - } MBCoding(current, pMB, qcoeff, bs, ¤t->sStat); stop_coding_timer(); continue; @@ -1686,16 +1665,14 @@ pParam->height, pParam->edged_width, (current->vol_flags & XVID_VOL_QUARTERPEL), - (current->vop_flags & XVID_VOP_REDUCED), current->rounding_type); stop_comp_timer(); pMB->field_pred = 0; - if (pMB->mode != MODE_NOT_CODED) - { pMB->cbp = - MBTransQuantInter(&pEnc->mbParam, current, pMB, x, y, + if (pMB->cbp != 0) { + pMB->cbp = MBTransQuantInter(&pEnc->mbParam, current, pMB, x, y, dct_codes, qcoeff); } @@ -1715,141 +1692,62 @@ /* Finished processing the MB, now check if to CODE or SKIP */ - skip_possible = (pMB->cbp == 0) && (pMB->mode == MODE_INTER) && - (pMB->dquant == 0); + skip_possible = (pMB->cbp == 0) && (pMB->mode == MODE_INTER); if (current->coding_type == S_VOP) skip_possible &= (pMB->mcsel == 1); - else if (current->coding_type == P_VOP) { - if ((pParam->vol_flags & XVID_VOL_QUARTERPEL)) - skip_possible &= ( (pMB->qmvs[0].x == 0) && (pMB->qmvs[0].y == 0) ); - else - skip_possible &= ( (pMB->mvs[0].x == 0) && (pMB->mvs[0].y == 0) ); + else { /* PVOP */ + const VECTOR * const mv = (pParam->vol_flags & XVID_VOL_QUARTERPEL) ? + pMB->qmvs : pMB->mvs; + skip_possible &= ((mv->x|mv->y) == 0); } - if ( (pMB->mode == MODE_NOT_CODED) || (skip_possible)) { + 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; -/* This is a candidate for SKIPping, but for P-VOPs check intermediate B-frames first */ + if (current->coding_type == P_VOP) { /* special rule for P-VOP's SKIP */ - if (current->coding_type == P_VOP) /* special rule for P-VOP's SKIP */ - { - int bSkip = 1; - - for (k=pEnc->bframenum_head; k< pEnc->bframenum_tail; k++) - { + for (k = pEnc->bframenum_head; k < pEnc->bframenum_tail; k++) { int iSAD; iSAD = sad16(reference->image.y + 16*y*pParam->edged_width + 16*x, - pEnc->bframes[k]->image.y + 16*y*pParam->edged_width + 16*x, - pParam->edged_width,BFRAME_SKIP_THRESHHOLD); - if (iSAD >= BFRAME_SKIP_THRESHHOLD * pMB->quant) - { bSkip = 0; + pEnc->bframes[k]->image.y + 16*y*pParam->edged_width + 16*x, + pParam->edged_width, BFRAME_SKIP_THRESHHOLD * pMB->quant); + if (iSAD >= BFRAME_SKIP_THRESHHOLD * pMB->quant) { + bSkip = 0; /* could not SKIP */ + if (pParam->vol_flags & XVID_VOL_QUARTERPEL) { + VECTOR predMV = get_qpmv2(current->mbs, pParam->mb_width, 0, x, y, 0); + pMB->pmvs[0].x = - predMV.x; + pMB->pmvs[0].y = - predMV.y; + } else { + VECTOR predMV = get_pmv2(current->mbs, pParam->mb_width, 0, x, y, 0); + pMB->pmvs[0].x = - predMV.x; + pMB->pmvs[0].y = - predMV.y; + } + pMB->mode = MODE_INTER; + pMB->cbp = 0; break; } } - - if (!bSkip) { /* no SKIP, but trivial block */ - if((pParam->vol_flags & XVID_VOL_QUARTERPEL)) { - VECTOR predMV = get_qpmv2(current->mbs, pParam->mb_width, 0, x, y, 0); - pMB->pmvs[0].x = - predMV.x; - pMB->pmvs[0].y = - predMV.y; - } - else { - VECTOR predMV = get_pmv2(current->mbs, pParam->mb_width, 0, x, y, 0); - pMB->pmvs[0].x = - predMV.x; - pMB->pmvs[0].y = - predMV.y; - } - pMB->mode = MODE_INTER; - pMB->cbp = 0; - MBCoding(current, pMB, qcoeff, bs, ¤t->sStat); - stop_coding_timer(); - - continue; /* next MB */ - } } - /* do SKIP */ - - pMB->mode = MODE_NOT_CODED; - MBSkip(bs); - stop_coding_timer(); - continue; /* next MB */ - } - /* ordinary case: normal coded INTER/INTER4V block */ - - if ((current->vop_flags & XVID_VOP_GREYSCALE)) - { pMB->cbp &= 0x3C; /* keep only bits 5-2 */ - qcoeff[4*64+0]=0; /* zero, because DC for INTRA MBs DC value is saved */ - qcoeff[5*64+0]=0; - } - - if((pParam->vol_flags & XVID_VOL_QUARTERPEL)) { - VECTOR predMV = get_qpmv2(current->mbs, pParam->mb_width, 0, x, y, 0); - pMB->pmvs[0].x = pMB->qmvs[0].x - predMV.x; - pMB->pmvs[0].y = pMB->qmvs[0].y - predMV.y; - DPRINTF(XVID_DEBUG_MV,"mv_diff (%i,%i) pred (%i,%i) result (%i,%i)\n", pMB->pmvs[0].x, pMB->pmvs[0].y, predMV.x, predMV.y, pMB->mvs[0].x, pMB->mvs[0].y); - } else { - VECTOR predMV = get_pmv2(current->mbs, pParam->mb_width, 0, x, y, 0); - pMB->pmvs[0].x = pMB->mvs[0].x - predMV.x; - pMB->pmvs[0].y = pMB->mvs[0].y - predMV.y; - DPRINTF(XVID_DEBUG_MV,"mv_diff (%i,%i) pred (%i,%i) result (%i,%i)\n", pMB->pmvs[0].x, pMB->pmvs[0].y, predMV.x, predMV.y, pMB->mvs[0].x, pMB->mvs[0].y); - } - - - if (pMB->mode == MODE_INTER4V) - { int k; - for (k=1;k<4;k++) - { - if((pParam->vol_flags & XVID_VOL_QUARTERPEL)) { - VECTOR predMV = get_qpmv2(current->mbs, pParam->mb_width, 0, x, y, k); - pMB->pmvs[k].x = pMB->qmvs[k].x - predMV.x; - pMB->pmvs[k].y = pMB->qmvs[k].y - predMV.y; - DPRINTF(XVID_DEBUG_MV,"mv_diff (%i,%i) pred (%i,%i) result (%i,%i)\n", pMB->pmvs[k].x, pMB->pmvs[k].y, predMV.x, predMV.y, pMB->mvs[k].x, pMB->mvs[k].y); - } else { - VECTOR predMV = get_pmv2(current->mbs, pParam->mb_width, 0, x, y, k); - pMB->pmvs[k].x = pMB->mvs[k].x - predMV.x; - pMB->pmvs[k].y = pMB->mvs[k].y - predMV.y; - DPRINTF(XVID_DEBUG_MV,"mv_diff (%i,%i) pred (%i,%i) result (%i,%i)\n", pMB->pmvs[k].x, pMB->pmvs[k].y, predMV.x, predMV.y, pMB->mvs[k].x, pMB->mvs[k].y); - } + if (bSkip) { + /* do SKIP */ + pMB->mode = MODE_NOT_CODED; + MBSkip(bs); + stop_coding_timer(); + continue; /* next MB */ } } + /* ordinary case: normal coded INTER/INTER4V block */ MBCoding(current, pMB, qcoeff, bs, &pEnc->current->sStat); stop_coding_timer(); - } } - if ((current->vop_flags & XVID_VOP_REDUCED)) - { - image_deblock_rrv(¤t->image, pParam->edged_width, - current->mbs, mb_width, mb_height, pParam->mb_width, - 16, 0); - } - emms(); - - if (current->sStat.iMvCount == 0) - current->sStat.iMvCount = 1; - - fSigma = (float) sqrt((float) current->sStat.iMvSum / current->sStat.iMvCount); - - iSearchRange = 1 << (3 + pParam->m_fcode); - - if ((fSigma > iSearchRange / 3) - && (pParam->m_fcode <= (3 + (pParam->vol_flags & XVID_VOL_QUARTERPEL?1:0) ))) /* maximum search range 128 */ - { - pParam->m_fcode++; - iSearchRange *= 2; - } else if ((fSigma < iSearchRange / 6) - && (pEnc->fMvPrevSigma >= 0) - && (pEnc->fMvPrevSigma < iSearchRange / 6) - && (pParam->m_fcode >= (2 + (pParam->vol_flags & XVID_VOL_QUARTERPEL?1:0) ))) /* minimum search range 16 */ - { - pParam->m_fcode--; - iSearchRange /= 2; - } - - pEnc->fMvPrevSigma = fSigma; + updateFcode(¤t->sStat, pEnc); /* frame drop code */ #if 0 @@ -1934,8 +1832,6 @@ fprintf(fp,"Y=%3d X=%3d MB=%2d CBP=%02X\n",y,x,mb->mode,mb->cbp); \ } - /* XXX: pEnc->current->global_flags &= ~XVID_VOP_REDUCED; reduced resoltion not yet supported */ - if (!first){ fp=fopen("C:\\XVIDDBGE.TXT","w"); } @@ -2006,36 +1902,35 @@ if (mb->mode == MODE_NOT_CODED) { if (pEnc->mbParam.plugin_flags & XVID_REQORIGINAL) { MBMotionCompensation(mb, x, y, f_ref, NULL, f_ref, NULL, NULL, &frame->image, - NULL, 0, 0, pEnc->mbParam.edged_width, 0, 0, 0); + NULL, 0, 0, pEnc->mbParam.edged_width, 0, 0); } - continue; } - if (mb->mode != MODE_DIRECT_NONE_MV || pEnc->mbParam.plugin_flags & XVID_REQORIGINAL) { + mb->quant = frame->quant; + + if (mb->cbp != 0 || pEnc->mbParam.plugin_flags & XVID_REQORIGINAL) { + /* we have to motion-compensate, transfer etc, + because there might be blocks to code */ + MBMotionCompensationBVOP(&pEnc->mbParam, mb, x, y, &frame->image, - f_ref, &pEnc->f_refh, &pEnc->f_refv, - &pEnc->f_refhv, b_ref, &pEnc->vInterH, - &pEnc->vInterV, &pEnc->vInterHV, - dct_codes); - - if (mb->mode == MODE_DIRECT_NO4V) mb->mode = MODE_DIRECT; - mb->quant = frame->quant; - - if (mb->mode != MODE_DIRECT_NONE_MV) - mb->cbp = MBTransQuantInterBVOP(&pEnc->mbParam, frame, mb, x, y, dct_codes, qcoeff); - - if ( (mb->mode == MODE_DIRECT) && (mb->cbp == 0) - && (mb->pmvs[3].x == 0) && (mb->pmvs[3].y == 0) ) { - mb->mode = MODE_DIRECT_NONE_MV; /* skipped */ - } + f_ref, &pEnc->f_refh, &pEnc->f_refv, + &pEnc->f_refhv, b_ref, &pEnc->vInterH, + &pEnc->vInterV, &pEnc->vInterHV, + dct_codes); + + mb->cbp = MBTransQuantInterBVOP(&pEnc->mbParam, frame, mb, x, y, dct_codes, qcoeff); } + + if (mb->mode == MODE_DIRECT_NO4V) + mb->mode = MODE_DIRECT; - /* keep only bits 5-2 -- Chroma blocks will just be skipped by the - * coding function for BFrames, that's why we don't zero teh DC - * coeffs */ - if ((frame->vop_flags & XVID_VOP_GREYSCALE)) - mb->cbp &= 0x3C; + if (mb->mode == MODE_DIRECT && (mb->cbp | mb->pmvs[3].x | mb->pmvs[3].y) == 0) + mb->mode = MODE_DIRECT_NONE_MV; /* skipped */ + else + if (frame->vop_flags & XVID_VOP_GREYSCALE) + /* keep only bits 5-2 -- Chroma blocks will just be skipped by MBCodingBVOP */ + mb->cbp &= 0x3C; start_timer(); MBCodingBVOP(frame, mb, qcoeff, frame->fcode, frame->bcode, bs, @@ -2046,8 +1941,6 @@ emms(); - /* TODO: dynamic fcode/bcode ??? */ - BitstreamPadAlways(bs); /* next_start_code() at the end of VideoObjectPlane() */ frame->length = (BitstreamPos(bs) - bits) / 8;