--- trunk/xvidcore/src/encoder.c 2002/05/03 15:26:30 158 +++ trunk/xvidcore/src/encoder.c 2002/06/09 13:16:26 192 @@ -32,9 +32,11 @@ * * History * + * 08.05.2002 fix some problem in DEBUG mode; + * MinChen * 14.04.2002 added FrameCodeB() * - * $Id: encoder.c,v 1.34 2002-05-03 15:26:30 edgomez Exp $ + * $Id: encoder.c,v 1.39 2002-06-09 13:16:26 edgomez Exp $ * ***************************************************************************/ @@ -62,10 +64,22 @@ #define ENC_CHECK(X) if(!(X)) return XVID_ERR_FORMAT #define SWAP(A,B) { void * tmp = A; A = B; B = tmp; } +static int FrameCodeI(Encoder * pEnc, + Bitstream * bs, + uint32_t *pBits); + +static int FrameCodeP(Encoder * pEnc, + Bitstream * bs, + uint32_t *pBits, + bool force_inter, + bool vol_header); -static int FrameCodeI(Encoder * pEnc, Bitstream * bs, uint32_t *pBits); -static int FrameCodeP(Encoder * pEnc, Bitstream * bs, uint32_t *pBits, bool force_inter, bool vol_header); -static void FrameCodeB(Encoder * pEnc, FRAMEINFO * frame, Bitstream * bs, uint32_t *pBits); +#ifdef BFRAMES +static void FrameCodeB(Encoder * pEnc, + FRAMEINFO * frame, + Bitstream * bs, + uint32_t *pBits); +#endif static int DQtab[4] = { @@ -98,14 +112,18 @@ ENC_CHECK(!(pParam->width % 2)); ENC_CHECK(!(pParam->height % 2)); + /* Fps */ + if (pParam->fincr <= 0 || pParam->fbase <= 0) { pParam->fincr = 1; pParam->fbase = 25; } - // simplify the "fincr/fbase" fraction - // (neccessary, since windows supplies us with huge numbers) + /* + * Simplify the "fincr/fbase" fraction + * (neccessary, since windows supplies us with huge numbers) + */ i = pParam->fincr; while (i > 1) @@ -127,6 +145,8 @@ pParam->fincr = (int)(pParam->fincr / div); } + /* Bitrate allocator defaults */ + if (pParam->rc_bitrate <= 0) pParam->rc_bitrate = 900000; @@ -139,19 +159,25 @@ if (pParam->rc_buffer <= 0) pParam->rc_buffer = 100; + /* Max and min quantizers */ + if ((pParam->min_quantizer <= 0) || (pParam->min_quantizer > 31)) pParam->min_quantizer = 1; if ((pParam->max_quantizer <= 0) || (pParam->max_quantizer > 31)) pParam->max_quantizer = 31; - if (pParam->max_key_interval == 0) /* 1 keyframe each 10 seconds */ - pParam->max_key_interval = 10 * pParam->fincr / pParam->fbase; - if (pParam->max_quantizer < pParam->min_quantizer) pParam->max_quantizer = pParam->min_quantizer; - if ((pEnc = (Encoder *) xvid_malloc(sizeof(Encoder), CACHE_LINE)) == NULL) + /* 1 keyframe each 10 seconds */ + + if (pParam->max_key_interval == 0) + pParam->max_key_interval = 10 * pParam->fincr / pParam->fbase; + + + pEnc = (Encoder *) xvid_malloc(sizeof(Encoder), CACHE_LINE); + if (pEnc == NULL) return XVID_ERR_MEMORY; /* Fill members of Encoder structure */ @@ -162,8 +188,8 @@ pEnc->mbParam.mb_width = (pEnc->mbParam.width + 15) / 16; pEnc->mbParam.mb_height = (pEnc->mbParam.height + 15) / 16; - pEnc->mbParam.edged_width = 16 * pEnc->mbParam.mb_width + 2 * EDGE_SIZE; - pEnc->mbParam.edged_height = 16 * pEnc->mbParam.mb_height + 2 * EDGE_SIZE; + pEnc->mbParam.edged_width = 16*pEnc->mbParam.mb_width + 2*EDGE_SIZE; + pEnc->mbParam.edged_height = 16*pEnc->mbParam.mb_height + 2*EDGE_SIZE; pEnc->mbParam.fbase = pParam->fbase; pEnc->mbParam.fincr = pParam->fincr; @@ -179,29 +205,25 @@ /* try to allocate frame memory */ - pEnc->current = NULL; - pEnc->reference = NULL; - if ( (pEnc->current = xvid_malloc(sizeof(FRAMEINFO), CACHE_LINE)) == NULL || - (pEnc->reference = xvid_malloc(sizeof(FRAMEINFO), CACHE_LINE)) == NULL) - { - if (pEnc->current) xvid_free(pEnc->current); - xvid_free(pEnc); - return XVID_ERR_MEMORY; - } + pEnc->current = xvid_malloc(sizeof(FRAMEINFO), CACHE_LINE); + pEnc->reference = xvid_malloc(sizeof(FRAMEINFO), CACHE_LINE); + + if ( pEnc->current == NULL || pEnc->reference == NULL) + goto xvid_err_memory1; /* try to allocate mb memory */ - pEnc->current->mbs = NULL; - pEnc->reference->mbs = NULL; + pEnc->current->mbs = xvid_malloc(sizeof(MACROBLOCK) * \ + pEnc->mbParam.mb_width * \ + pEnc->mbParam.mb_height, + CACHE_LINE); + pEnc->reference->mbs = xvid_malloc(sizeof(MACROBLOCK) * \ + pEnc->mbParam.mb_width * \ + pEnc->mbParam.mb_height, + CACHE_LINE); - if ((pEnc->current->mbs = xvid_malloc(sizeof(MACROBLOCK) * pEnc->mbParam.mb_width * pEnc->mbParam.mb_height, CACHE_LINE)) == NULL || - (pEnc->reference->mbs = xvid_malloc(sizeof(MACROBLOCK) * pEnc->mbParam.mb_width * pEnc->mbParam.mb_height, CACHE_LINE)) == NULL) - { - if (pEnc->current->mbs) xvid_free(pEnc->current->mbs); - xvid_free(pEnc->current); - xvid_free(pEnc->reference); - xvid_free(pEnc); - } + if (pEnc->current->mbs == NULL || pEnc->reference->mbs == NULL) + goto xvid_err_memory2; /* try to allocate image memory */ @@ -220,69 +242,106 @@ image_null(&pEnc->vInterVf); image_null(&pEnc->vInterHV); image_null(&pEnc->vInterHVf); - - if ( -#ifdef _DEBUG - image_create(&pEnc->sOriginal, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0 || -#endif -#ifdef BFRAMES - image_create(&pEnc->f_refh, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0 || - image_create(&pEnc->f_refv, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0 || - image_create(&pEnc->f_refhv, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0 || -#endif - image_create(&pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0 || - image_create(&pEnc->reference->image, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0 || - image_create(&pEnc->vInterH, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0 || - image_create(&pEnc->vInterV, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0 || - image_create(&pEnc->vInterVf, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0 || - image_create(&pEnc->vInterHV, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0 || - image_create(&pEnc->vInterHVf, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0) - { + #ifdef _DEBUG - image_destroy(&pEnc->sOriginal, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); + if (image_create(&pEnc->sOriginal, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height) < 0) + goto xvid_err_memory3; #endif #ifdef BFRAMES - image_destroy(&pEnc->f_refh, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->f_refv, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->f_refhv, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); + if (image_create(&pEnc->f_refh, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height) < 0) + goto xvid_err_memory3; + if (image_create(&pEnc->f_refv, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height) < 0) + goto xvid_err_memory3; + if (image_create(&pEnc->f_refhv, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height) < 0) + goto xvid_err_memory3; #endif - image_destroy(&pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->reference->image, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->vInterH, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->vInterV, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->vInterVf, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->vInterHV, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->vInterHVf, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - - xvid_free(pEnc->current); - xvid_free(pEnc->reference); - xvid_free(pEnc); - return XVID_ERR_MEMORY; - } + if (image_create(&pEnc->current->image, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height) < 0) + goto xvid_err_memory3; + if (image_create(&pEnc->reference->image, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height) < 0) + goto xvid_err_memory3; + if (image_create(&pEnc->vInterH, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height) < 0) + goto xvid_err_memory3; + if (image_create(&pEnc->vInterV, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height) < 0) + goto xvid_err_memory3; + if (image_create(&pEnc->vInterVf, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height) < 0) + goto xvid_err_memory3; + if (image_create(&pEnc->vInterHV, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height) < 0) + goto xvid_err_memory3; + if (image_create(&pEnc->vInterHVf, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height) < 0) + goto xvid_err_memory3; + + -// ============================================================================== + /* B Frames specific init */ #ifdef BFRAMES - // TODO: handle malloc() == NULL - pEnc->max_bframes = pParam->max_bframes; + pEnc->mbParam.max_bframes = pParam->max_bframes; pEnc->bquant_ratio = pParam->bquant_ratio; - if (pEnc->max_bframes > 0) + pEnc->bframes = NULL; + + if (pEnc->mbParam.max_bframes > 0) { int n; - pEnc->bframes = malloc(pEnc->max_bframes * sizeof(FRAMEINFO *)); + pEnc->bframes = xvid_malloc(pEnc->mbParam.max_bframes * \ + sizeof(FRAMEINFO *), + CACHE_LINE); + + if (pEnc->bframes == NULL) + goto xvid_err_memory3; - for (n = 0; n < pEnc->max_bframes; n++) + for (n=0; nmbParam.max_bframes; n++) + pEnc->bframes[n] = NULL; + + + for (n = 0; n < pEnc->mbParam.max_bframes; n++) { - pEnc->bframes[n] = malloc(sizeof(FRAMEINFO)); - pEnc->bframes[n]->mbs = malloc(sizeof(MACROBLOCK) * pEnc->mbParam.mb_width * pEnc->mbParam.mb_height); + pEnc->bframes[n] = xvid_malloc(sizeof(FRAMEINFO), + CACHE_LINE); + + if (pEnc->bframes[n] == NULL) + goto xvid_err_memory4; + + pEnc->bframes[n]->mbs = xvid_malloc(sizeof(MACROBLOCK) * \ + pEnc->mbParam.mb_width * \ + pEnc->mbParam.mb_height, + CACHE_LINE); + + if (pEnc->bframes[n]->mbs == NULL) + goto xvid_err_memory4; + + image_null(&pEnc->bframes[n]->image); + + if (image_create(&pEnc->bframes[n]->image, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height) < 0) + goto xvid_err_memory4; - if (image_create(&pEnc->bframes[n]->image, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0) - { - return XVID_ERR_MEMORY; - } } } + pEnc->bframenum_head = 0; pEnc->bframenum_tail = 0; pEnc->flush_bframes = 0; @@ -291,60 +350,173 @@ pEnc->mbParam.m_ticks = 0; #endif - -// ============================================================================== - - pParam->handle = (void *)pEnc; if (pParam->rc_bitrate) { - RateControlInit(pParam->rc_bitrate, pParam->rc_reaction_delay_factor, - pParam->rc_averaging_period, pParam->rc_buffer, pParam->fbase * 1000 / pParam->fincr, - pParam->max_quantizer, pParam->min_quantizer); + RateControlInit(&pEnc->rate_control, + pParam->rc_bitrate, + pParam->rc_reaction_delay_factor, + pParam->rc_averaging_period, + pParam->rc_buffer, + pParam->fbase * 1000 / pParam->fincr, + pParam->max_quantizer, + pParam->min_quantizer); } init_timer(); return XVID_ERR_OK; -} + /* + * We handle all XVID_ERR_MEMORY here, this makes the code lighter + * + * ToDo?: We could avoid that piece of code if encoder_destroy could + * handle different destroy levels + */ +#ifdef BFRAMES + xvid_err_memory4: + for (i=0; imbParam.max_bframes; i++) + { + + if (pEnc->bframes[i] == NULL) continue; + + image_destroy(&pEnc->bframes[i]->image, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + + xvid_free(pEnc->bframes[i]->mbs); + + xvid_free(pEnc->bframes[i]); + + } + + xvid_free(pEnc->bframes); + +#endif + + xvid_err_memory3: +#ifdef _DEBUG + image_destroy(&pEnc->sOriginal, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); +#endif + +#ifdef BFRAMES + image_destroy(&pEnc->f_refh, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->f_refv, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->f_refhv, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); +#endif + + image_destroy(&pEnc->current->image, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->reference->image, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->vInterH, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->vInterV, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->vInterVf, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->vInterHV, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->vInterHVf, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + + xvid_err_memory2: + xvid_free(pEnc->current->mbs); + xvid_free(pEnc->reference->mbs); + + xvid_err_memory1: + xvid_free(pEnc->current); + xvid_free(pEnc->reference); + xvid_free(pEnc); + + return XVID_ERR_MEMORY; +} int encoder_destroy(Encoder * pEnc) { ENC_CHECK(pEnc); -// ================================================================= + /* B Frames specific */ #ifdef BFRAMES - if (pEnc->max_bframes > 0) + int i; + + for (i=0; imbParam.max_bframes; i++) { - int n; - for (n = 0; n < pEnc->max_bframes; n++) - { - image_destroy(&pEnc->bframes[n]->image, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - free(pEnc->bframes[n]->mbs); - free(pEnc->bframes[n]); - } - free(pEnc->bframes); + + if (pEnc->bframes[i] == NULL) continue; + + image_destroy(&pEnc->bframes[i]->image, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + + xvid_free(pEnc->bframes[i]->mbs); + + xvid_free(pEnc->bframes[i]); + } + + xvid_free(pEnc->bframes); + #endif -//==================================================================== - image_destroy(&pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->reference->image, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->vInterH, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->vInterV, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->vInterVf, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->vInterHV, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->vInterHVf, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); + /* All images, reference, current etc ... */ + + image_destroy(&pEnc->current->image, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->reference->image, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->vInterH, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->vInterV, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->vInterVf, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->vInterHV, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->vInterHVf, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); #ifdef BFRAMES - image_destroy(&pEnc->f_refh, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->f_refv, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); - image_destroy(&pEnc->f_refhv, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); + image_destroy(&pEnc->f_refh, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->f_refv, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); + image_destroy(&pEnc->f_refhv, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); #endif #ifdef _DEBUG - image_destroy(&pEnc->sOriginal, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); + image_destroy(&pEnc->sOriginal, + pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); #endif + + /* Encoder structure */ + xvid_free(pEnc->current->mbs); xvid_free(pEnc->current); @@ -352,6 +524,7 @@ xvid_free(pEnc->reference); xvid_free(pEnc); + return XVID_ERR_OK; } @@ -365,6 +538,11 @@ Bitstream bs; uint32_t bits; +#ifdef _DEBUG + float psnr; + char temp[128]; +#endif + ENC_CHECK(pEnc); ENC_CHECK(pFrame); @@ -384,7 +562,7 @@ { // we have reached end of stream without getting a future reference // .. so encode last final frame a pframe - dprintf("--- PFRAME (final frame correction) --- "); + //dprintf("--- PFRAME (final frame correction) --- "); pEnc->bframenum_tail--; SWAP(pEnc->current, pEnc->reference); @@ -399,7 +577,7 @@ return XVID_ERR_OK; } - dprintf("--- BFRAME (flush) --- "); + //dprintf("--- BFRAME (flush) --- "); FrameCodeB(pEnc, pEnc->bframes[pEnc->bframenum_head], &bs, &bits); @@ -432,7 +610,7 @@ SWAP(pEnc->current, pEnc->reference); - pEnc->current->quant = (pFrame->quant == 0) ? RateControlGetQ(0) : pFrame->quant; + pEnc->current->quant = (pFrame->quant == 0) ? RateControlGetQ(&pEnc->rate_control, 0) : pFrame->quant; if(pEnc->current->quant < 1) pEnc->current->quant = 1; @@ -457,7 +635,7 @@ stop_conv_timer(); #ifdef _DEBUG - image_copy(&pEnc->sOriginal, &pEnc->sCurrent, pEnc->mbParam.edged_width, pEnc->mbParam.height); + image_copy(&pEnc->sOriginal, &pEnc->current->image, pEnc->mbParam.edged_width, pEnc->mbParam.height); #endif @@ -497,7 +675,7 @@ (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) { - dprintf("--- IFRAME ---"); + //dprintf("--- IFRAME ---"); FrameCodeI(pEnc, &bs, &bits); @@ -507,9 +685,9 @@ /* note: sequences like "IIBB" decode fine with msfdam but, go screwy with divx5.00 */ } - else if (pEnc->bframenum_tail >= pEnc->max_bframes) + else if (pEnc->bframenum_tail >= pEnc->mbParam.max_bframes) { - dprintf("--- PFRAME ---"); + //dprintf("--- PFRAME ---"); FrameCodeP(pEnc, &bs, &bits, 1, 0); pFrame->intra = 0; @@ -517,7 +695,7 @@ } else { - dprintf("--- BFRAME (store) --- head=%i tail=%i", pEnc->bframenum_head, pEnc->bframenum_tail); + //dprintf("--- BFRAME (store) --- head=%i tail=%i", pEnc->bframenum_head, pEnc->bframenum_tail); if (pFrame->bquant < 1) { @@ -569,7 +747,10 @@ if (pFrame->quant == 0) { - RateControlUpdate(pEnc->current->quant, pFrame->length, pFrame->intra); + RateControlUpdate(&pEnc->rate_control, + pEnc->current->quant, + pFrame->length, + pFrame->intra); } pEnc->iFrameNum++; @@ -630,7 +811,7 @@ if (pFrame->quant == 0) { - pEnc->current->quant = RateControlGetQ(0); + pEnc->current->quant = RateControlGetQ(&pEnc->rate_control,0); } else { @@ -723,7 +904,10 @@ if (pFrame->quant == 0) { - RateControlUpdate(pEnc->current->quant, pFrame->length, pFrame->intra); + RateControlUpdate(&pEnc->rate_control, + pEnc->current->quant, + pFrame->length, + pFrame->intra); } #ifdef _DEBUG @@ -1351,4 +1535,4 @@ *pBits = BitstreamPos(bs) - *pBits; } -#endif \ No newline at end of file +#endif