--- branches/dev-api-3/xvidcore/src/encoder.c 2002/09/26 01:54:54 543 +++ branches/dev-api-3/xvidcore/src/encoder.c 2002/10/17 19:10:57 602 @@ -39,7 +39,7 @@ * MinChen * 14.04.2002 added FrameCodeB() * - * $Id: encoder.c,v 1.76.2.2 2002-09-26 01:54:54 h Exp $ + * $Id: encoder.c,v 1.76.2.13 2002-10-17 19:10:57 Isibaar Exp $ * ****************************************************************************/ @@ -410,12 +410,11 @@ pEnc->queue_tail = 0; pEnc->queue_size = 0; + pEnc->mbParam.m_stamp = 0; - pEnc->mbParam.m_seconds = 0; - pEnc->mbParam.m_ticks = 0; pEnc->m_framenum = 0; - pEnc->last_pframe = 0; - pEnc->last_sync = 0; + pEnc->current->stamp = 0; + pEnc->reference->stamp = 0; pParam->handle = (void *) pEnc; @@ -604,15 +603,8 @@ static __inline void inc_frame_num(Encoder * pEnc) { - pEnc->mbParam.m_ticks += pEnc->mbParam.fincr; - - pEnc->mbParam.m_ticks = pEnc->mbParam.m_ticks % pEnc->mbParam.fbase; - if (pEnc->mbParam.m_ticks < pEnc->last_sync) - pEnc->mbParam.m_seconds = 1; - // more than 1 second since last I or P is not supported. - else - pEnc->mbParam.m_seconds = 0; - + pEnc->current->stamp = pEnc->mbParam.m_stamp; // first frame is zero + pEnc->mbParam.m_stamp += pEnc->mbParam.fincr; } @@ -641,6 +633,27 @@ pEnc->queue_tail = (pEnc->queue_tail + 1) % pEnc->mbParam.max_bframes; } +static __inline void +set_timecodes(FRAMEINFO* pCur,FRAMEINFO *pRef, int32_t time_base) +{ + + pCur->ticks = (int32_t)pCur->stamp % time_base; + pCur->seconds = ((int32_t)pCur->stamp / time_base) - ((int32_t)pRef->stamp / time_base) ; + + //HEAVY DEBUG OUTPUT remove when timecodes prove to be stable + +/* 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); + +*/ +} + + + /***************************************************************************** @@ -659,7 +672,7 @@ { uint16_t x, y; Bitstream bs; - uint32_t bits; + uint32_t bits, mode; int input_valid = 1; @@ -731,15 +744,26 @@ 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); - 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; @@ -801,21 +825,20 @@ 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) { - 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); return XVID_ERR_OK; @@ -846,9 +869,6 @@ pEnc->current->fcode = pEnc->mbParam.m_fcode; pEnc->current->bcode = pEnc->mbParam.m_fcode; - pEnc->current->seconds = pEnc->mbParam.m_seconds; - pEnc->current->ticks = pEnc->mbParam.m_ticks; - inc_frame_num(pEnc); #ifdef _DEBUG_PSNR @@ -860,7 +880,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); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -907,9 +927,12 @@ 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, + || /*image_mad(&pEnc->reference->image, &pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.width, - pEnc->mbParam.height) > 30) { + pEnc->mbParam.height) > 30) {*/ + 2 == (mode = MEanalysis(&pEnc->reference->image, &pEnc->current->image, + &pEnc->mbParam, pEnc->current->mbs, pEnc->current->fcode))) { + /* * This will be coded as an Intra Frame */ @@ -948,7 +971,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; } @@ -957,7 +980,7 @@ * NB : sequences like "IIBB" decode fine with msfdam but, * go screwy with divx 5.00 */ - } else if (pEnc->bframenum_tail >= pEnc->mbParam.max_bframes) { + } else if (pEnc->bframenum_tail >= pEnc->mbParam.max_bframes || mode != 0) { /* * This will be coded as a Predicted Frame */ @@ -975,7 +998,7 @@ pEnc->flush_bframes = 1; if ((pEnc->global & XVID_GLOBAL_PACKED)) { - BitstreamPad(&bs); + BitstreamPadAlways(&bs); input_valid = 0; goto ipvop_loop; } @@ -1052,7 +1075,6 @@ pFrame->length, pFrame->intra); } - stop_global_timer(); write_timer(); @@ -1096,10 +1118,10 @@ pEnc->current->global_flags = pFrame->general; pEnc->current->motion_flags = pFrame->motion; - pEnc->current->seconds = pEnc->mbParam.m_seconds; - pEnc->current->ticks = pEnc->mbParam.m_ticks; 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)) @@ -1129,6 +1151,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 * @@ -1234,7 +1261,6 @@ DEBUG(temp); #endif - inc_frame_num(pEnc); pEnc->iFrameNum++; stop_global_timer(); @@ -1491,6 +1517,11 @@ 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); *pBits = BitstreamPos(bs); @@ -1531,9 +1562,6 @@ pEnc->sStat.iMvCount = 0; pEnc->mbParam.m_fcode = 2; - pEnc->last_pframe = pEnc->current->ticks; - pEnc->last_sync = pEnc->current->ticks; - if (pEnc->current->global_flags & XVID_HINTEDME_GET) { HintedMEGet(pEnc, 1); } @@ -1560,7 +1588,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; @@ -1586,6 +1614,7 @@ 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(); } @@ -1593,8 +1622,11 @@ 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 { @@ -1612,7 +1644,9 @@ if (vol_header) BitstreamWriteVolHeader(bs, &pEnc->mbParam, pEnc->current); + + set_timecodes(pEnc->current,pEnc->reference,pEnc->mbParam.fbase); BitstreamWriteVopHeader(bs, &pEnc->mbParam, pEnc->current, 1); *pBits = BitstreamPos(bs); @@ -1635,6 +1669,7 @@ dct_codes, pEnc->mbParam.width, pEnc->mbParam.height, pEnc->mbParam.edged_width, + pEnc->mbParam.m_quarterpel, pEnc->current->rounding_type); stop_comp_timer(); @@ -1680,10 +1715,15 @@ /* 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)) { + skip_possible = (pMB->cbp == 0) & (pMB->mode == MODE_INTER) & + (pMB->dquant == NO_CHANGE); + if(pEnc->mbParam.m_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); + + if ((pMB->mode == MODE_NOT_CODED) || (skip_possible)) { /* This is a candidate for SKIPping, but check intermediate B-frames first */ int bSkip = 1; @@ -1703,7 +1743,10 @@ if (!bSkip) { VECTOR predMV; - predMV = get_pmv2(pEnc->current->mbs, pEnc->mbParam.mb_width, 0, x, y, 0); + if(pEnc->mbParam.m_quarterpel) + predMV = get_qpmv2(pEnc->current->mbs, pEnc->mbParam.mb_width, 0, x, y, 0); + else + 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; pMB->mode = MODE_INTER; pMB->cbp = 0; @@ -1738,14 +1781,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; @@ -1753,7 +1796,7 @@ pEnc->sStat.fMvPrevSigma = fSigma; -#ifdef BFRAMES +#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 < @@ -1763,6 +1806,8 @@ pEnc->sStat.ublks = pEnc->mbParam.mb_width * pEnc->mbParam.mb_height; BitstreamReset(bs); + + set_timecodes(pEnc->current,pEnc->reference,pEnc->mbParam.fbase); BitstreamWriteVopHeader(bs, &pEnc->mbParam, pEnc->current, 0); // copy reference frame details into the current frame @@ -1779,10 +1824,6 @@ *pBits = BitstreamPos(bs) - *pBits; - pEnc->time_pp = ((int32_t)pEnc->mbParam.fbase - (int32_t)pEnc->last_pframe + (int32_t)pEnc->current->ticks) % - (int32_t)pEnc->mbParam.fbase; - pEnc->last_pframe = pEnc->current->ticks; - return 0; // inter } @@ -1819,7 +1860,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 @@ -1829,14 +1870,15 @@ 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(); + MotionEstimationBVOP(&pEnc->mbParam, frame, - ((int32_t)pEnc->mbParam.fbase + pEnc->last_pframe - frame->ticks) % pEnc->mbParam.fbase, - pEnc->time_pp, - pEnc->reference->mbs, f_ref, + ((int32_t)(pEnc->current->stamp - frame->stamp)), // time_bp + ((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->vInterV, &pEnc->vInterHV); @@ -1850,6 +1892,8 @@ } */ frame->coding_type = B_VOP; + + set_timecodes(frame, pEnc->reference,pEnc->mbParam.fbase); BitstreamWriteVopHeader(bs, &pEnc->mbParam, frame, 1); *pBits = BitstreamPos(bs);