--- branches/dev-api-3/xvidcore/src/encoder.c 2002/09/29 15:53:42 569 +++ branches/dev-api-3/xvidcore/src/encoder.c 2002/11/07 10:31:03 631 @@ -39,7 +39,7 @@ * MinChen * 14.04.2002 added FrameCodeB() * - * $Id: encoder.c,v 1.76.2.5 2002-09-29 15:53:42 chl Exp $ + * $Id: encoder.c,v 1.76.2.16 2002-11-07 10:28:15 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 * @@ -411,8 +402,10 @@ pEnc->queue_size = 0; pEnc->mbParam.m_stamp = 0; -; + pEnc->m_framenum = 0; + pEnc->current->stamp = 0; + pEnc->reference->stamp = 0; pParam->handle = (void *) pEnc; @@ -623,7 +616,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(); @@ -640,14 +633,14 @@ //HEAVY DEBUG OUTPUT remove when timecodes prove to be stable - fprintf(stderr,"WriteVop: %d - %d \n", +/* fprintf(stderr,"WriteVop: %d - %d \n", ((int32_t)pCur->stamp / time_base), ((int32_t)pRef->stamp / time_base)); fprintf(stderr,"set_timecodes: VOP %1d stamp=%lld ref_stamp=%lld base=%d\n", pCur->coding_type, pCur->stamp, pRef->stamp, time_base); fprintf(stderr,"set_timecodes: VOP %1d seconds=%d ticks=%d (ref-sec=%d ref-tick=%d)\n", pCur->coding_type, pCur->seconds, pCur->ticks, pRef->seconds, pRef->ticks); - +*/ } @@ -718,6 +711,8 @@ pFrame->length = BitstreamLength(&bs); pFrame->intra = 0; + emms(); + return XVID_ERR_OK; } @@ -736,22 +731,34 @@ if (input_valid) queue_image(pEnc, pFrame); + emms(); + return XVID_ERR_OK; } if (pEnc->bframenum_head > 0) { pEnc->bframenum_head = pEnc->bframenum_tail = 0; + /* write an empty marker to the bitstream. + + for divx5 decoder compatibility, this marker must consist + of a not-coded p-vop, with a time_base of zero, and time_increment + indentical to the future-referece frame. + */ + if ((pEnc->global & XVID_GLOBAL_PACKED)) { + int tmp; DPRINTF(DPRINTF_DEBUG,"*** EMPTY 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); - set_timecodes(pEnc->current,pEnc->reference,pEnc->mbParam.fbase); - BitstreamWriteVopHeader(&bs, &pEnc->mbParam, pEnc->current, 0); BitstreamPad(&bs); - BitstreamPutBits(&bs, 0x7f, 8); + + tmp = pEnc->current->seconds; + pEnc->current->seconds = 0; /* force time_base = 0 */ + BitstreamWriteVopHeader(&bs, &pEnc->mbParam, pEnc->current, 0); + pEnc->current->seconds = tmp; pFrame->length = BitstreamLength(&bs); pFrame->intra = 0; @@ -759,6 +766,8 @@ if (input_valid) queue_image(pEnc, pFrame); + emms(); + return XVID_ERR_OK; } } @@ -789,8 +798,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 @@ -813,24 +825,23 @@ pEnc->queue_head = (pEnc->queue_head + 1) % pEnc->mbParam.max_bframes; pEnc->queue_size--; - } else if (BitstreamPos(&bs) == 0) { + } else { - DPRINTF(DPRINTF_DEBUG,"*** SKIP 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 nothing was encoded, write an 'ignore this frame' flag + to the bitstream */ - pFrame->intra = 0; + if (BitstreamPos(&bs) == 0) { - set_timecodes(pEnc->current,pEnc->reference,pEnc->mbParam.fbase); - BitstreamWriteVopHeader(&bs, &pEnc->mbParam, pEnc->current, 0); // write N_VOP - BitstreamPad(&bs); - pFrame->length = BitstreamLength(&bs); - - return XVID_ERR_OK; + DPRINTF(DPRINTF_DEBUG,"*** SKIP 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); - } else { + BitstreamPutBits(&bs, 0x7f, 8); + pFrame->intra = 0; + } pFrame->length = BitstreamLength(&bs); + emms(); return XVID_ERR_OK; } @@ -870,7 +881,7 @@ if ((pEnc->global & XVID_GLOBAL_DEBUG)) { image_printf(&pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.height, 5, 5, - "%i if:%i st:%i:%i", pEnc->m_framenum++, pEnc->iFrameNum, pEnc->current->seconds, pEnc->current->ticks); + "%i if:%i st:%i", pEnc->m_framenum++, pEnc->iFrameNum, pEnc->current->stamp); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -961,7 +972,7 @@ pEnc->flush_bframes = 1; if ((pEnc->global & XVID_GLOBAL_PACKED) && pEnc->bframenum_tail > 0) { - BitstreamPad(&bs); + BitstreamPadAlways(&bs); input_valid = 0; goto ipvop_loop; } @@ -988,7 +999,7 @@ pEnc->flush_bframes = 1; if ((pEnc->global & XVID_GLOBAL_PACKED)) { - BitstreamPad(&bs); + BitstreamPadAlways(&bs); input_valid = 0; goto ipvop_loop; } @@ -1068,6 +1079,7 @@ stop_global_timer(); write_timer(); + emms(); return XVID_ERR_OK; } @@ -1110,6 +1122,8 @@ pEnc->current->motion_flags = pFrame->motion; pEnc->mbParam.hint = &pFrame->hint; + inc_frame_num(pEnc); + /* disable alternate scan flag if interlacing is not enabled */ if ((pEnc->current->global_flags & XVID_ALTERNATESCAN) && !(pEnc->current->global_flags & XVID_INTERLACING)) @@ -1120,7 +1134,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(); @@ -1139,6 +1153,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 * @@ -1244,7 +1263,6 @@ DEBUG(temp); #endif - inc_frame_num(pEnc); pEnc->iFrameNum++; stop_global_timer(); @@ -1493,6 +1511,7 @@ 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); @@ -1501,7 +1520,10 @@ if ((pEnc->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); @@ -1569,7 +1591,7 @@ int iLimit; int x, y, k; int iSearchRange; - int bIntra; + int bIntra, skip_possible; /* IMAGE *pCurrent = &pEnc->current->image; */ IMAGE *pRef = &pEnc->reference->image; @@ -1581,6 +1603,7 @@ 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) @@ -1595,29 +1618,41 @@ 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); - if (bIntra == 0) MotionEstimationHinted(&pEnc->mbParam, pEnc->current, pEnc->reference, + if (bIntra == 0) { + pEnc->current->fcode = FindFcode(&pEnc->mbParam, pEnc->current); + MotionEstimationHinted(&pEnc->mbParam, pEnc->current, pEnc->reference, &pEnc->vInterH, &pEnc->vInterV, &pEnc->vInterHV); + } } 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); @@ -1646,6 +1681,7 @@ dct_codes, pEnc->mbParam.width, pEnc->mbParam.height, pEnc->mbParam.edged_width, + pEnc->mbParam.m_quarterpel, pEnc->current->rounding_type); stop_comp_timer(); @@ -1691,36 +1727,56 @@ /* 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); } - else MBSkip(bs); + else + { + pMB->mode = MODE_NOT_CODED; + MBSkip(bs); + } } else { if (pEnc->current->global_flags & XVID_GREYSCALE) @@ -1749,14 +1805,14 @@ 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->mbParam.m_fcode >= (2 + pEnc->mbParam.m_quarterpel))) // minimum search range 16 { pEnc->mbParam.m_fcode--; iSearchRange /= 2; @@ -1782,6 +1838,7 @@ 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); @@ -1821,6 +1878,8 @@ } #endif + frame->quarterpel = pEnc->mbParam.m_quarterpel; + // forward image_setedges(f_ref, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height, pEnc->mbParam.width, @@ -1828,7 +1887,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 @@ -1838,7 +1897,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();