--- encoder.c 2003/03/30 00:36:53 1.95.2.17 +++ encoder.c 2003/06/09 19:20:56 1.95.2.28 @@ -1,32 +1,27 @@ /***************************************************************************** * * XVID MPEG-4 VIDEO CODEC - * - Encoder main module - + * - Encoder main module - * - * This program is an implementation of a part of one or more MPEG-4 - * Video tools as specified in ISO/IEC 14496-2 standard. Those intending - * to use this software module in hardware or software products are - * advised that its use may infringe existing patents or copyrights, and - * any such use would be at such party's own risk. The original - * developer of this software module and his/her company, and subsequent - * editors and their companies, will have no liability for use of this - * software or modifications or derivatives thereof. + * Copyright(C) 2002 Michael Militzer + * 2002-2003 Peter Ross + * 2002 Daniel Smith * - * This program is free software; you can redistribute it and/or modify + * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation ; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of + * but WITHOUT ANY WARRANTY ; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * 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.95.2.17 2003/03/30 00:36:53 edgomez Exp $ + * $Id: encoder.c,v 1.95.2.28 2003/06/09 19:20:56 edgomez Exp $ * ****************************************************************************/ @@ -49,7 +44,6 @@ #include "bitstream/mbcoding.h" #include "utils/emms.h" #include "bitstream/mbcoding.h" -#include "quant/adapt_quant.h" #include "quant/quant_matrix.h" #include "utils/mem_align.h" @@ -134,6 +128,8 @@ return XVID_ERR_MEMORY; memset(pEnc, 0, sizeof(Encoder)); + pEnc->mbParam.profile = create->profile; + /* global flags */ pEnc->mbParam.global_flags = create->global; @@ -151,11 +147,28 @@ if (pEnc->mbParam.fincr>0) simplify_time(&pEnc->mbParam.fincr, &pEnc->mbParam.fbase); - /* plugin */ - pEnc->num_plugins = create->num_plugins; - pEnc->plugins = xvid_malloc(sizeof(xvid_enc_plugin_t) * pEnc->num_plugins, CACHE_LINE); - if (pEnc->plugins == NULL) - goto xvid_err_memory0; + /* zones */ + if(create->num_zones > 0) { + pEnc->num_zones = create->num_zones; + pEnc->zones = xvid_malloc(sizeof(xvid_enc_zone_t) * pEnc->num_zones, CACHE_LINE); + if (pEnc->zones == NULL) + goto xvid_err_memory0; + memcpy(pEnc->zones, create->zones, sizeof(xvid_enc_zone_t) * pEnc->num_zones); + } else { + pEnc->num_zones = 0; + pEnc->zones = NULL; + } + + /* plugins */ + if(create->num_plugins > 0) { + pEnc->num_plugins = create->num_plugins; + pEnc->plugins = xvid_malloc(sizeof(xvid_enc_plugin_t) * pEnc->num_plugins, CACHE_LINE); + if (pEnc->plugins == NULL) + goto xvid_err_memory0; + } else { + pEnc->num_plugins = 0; + pEnc->plugins = NULL; + } for (n=0; nnum_plugins;n++) { xvid_plg_create_t pcreate; @@ -169,6 +182,8 @@ memset(&pcreate, 0, sizeof(xvid_plg_create_t)); pcreate.version = XVID_VERSION; + pcreate.num_zones = pEnc->num_zones; + pcreate.zones = pEnc->zones; pcreate.width = pEnc->mbParam.width; pcreate.height = pEnc->mbParam.height; pcreate.fincr = pEnc->mbParam.fincr; @@ -197,13 +212,19 @@ pEnc->mbParam.max_bframes = MAX(create->max_bframes, 0); pEnc->mbParam.bquant_ratio = MAX(create->bquant_ratio, 0); pEnc->mbParam.bquant_offset = create->bquant_offset; + + /* min/max quant */ + for (n=0; n<3; n++) { + pEnc->mbParam.min_quant[n] = create->min_quant[n] > 0 ? create->min_quant[n] : 2; + pEnc->mbParam.max_quant[n] = create->max_quant[n] > 0 ? create->max_quant[n] : 31; + } /* frame drop ratio */ pEnc->mbParam.frame_drop_ratio = MAX(create->frame_drop_ratio, 0); /* max keyframe interval */ - pEnc->mbParam.iMaxKeyInterval = create->max_key_interval <=0 ? 250 : create->max_key_interval; - /*XXX: replace 250 hard code with "10seconds * framerate" */ + pEnc->mbParam.iMaxKeyInterval = create->max_key_interval <= 0 ? + 10 * pEnc->mbParam.fbase / pEnc->mbParam.fincr : create->max_key_interval; /* Bitrate allocator defaults @@ -500,6 +521,8 @@ } xvid_free(pEnc->plugins); + xvid_free(pEnc->zones); + xvid_free(pEnc); create->handle = NULL; @@ -577,6 +600,8 @@ pEnc->mbParam.edged_height); image_destroy(&pEnc->f_refhv, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); + image_destroy(&pEnc->vGMC, pEnc->mbParam.edged_width, + pEnc->mbParam.edged_height); if ((pEnc->mbParam.plugin_flags & XVID_REQORIGINAL)) { image_destroy(&pEnc->sOriginal, pEnc->mbParam.edged_width, @@ -598,8 +623,7 @@ } - if (pEnc->num_plugins>0) - { + if (pEnc->num_plugins>0) { xvid_plg_destroy_t pdestroy; memset(&pdestroy, 0, sizeof(xvid_plg_destroy_t)); @@ -614,6 +638,9 @@ xvid_free(pEnc->plugins); } + if (pEnc->num_plugins>0) + xvid_free(pEnc->zones); + xvid_free(pEnc); return 0; /* ok */ @@ -635,12 +662,21 @@ memset(&data, 0, sizeof(xvid_plg_data_t)); data.version = XVID_VERSION; + /* find zone */ + for(i=0; inum_zones && pEnc->zones[i].frame<=frame->frame_num; i++) ; + data.zone = i>0 ? &pEnc->zones[i-1] : NULL; + data.width = pEnc->mbParam.width; data.height = pEnc->mbParam.height; data.mb_width = pEnc->mbParam.mb_width; data.mb_height = pEnc->mbParam.mb_height; data.fincr = frame->fincr; data.fbase = pEnc->mbParam.fbase; + + for (i=0; i<3; i++) { + data.min_quant[i] = pEnc->mbParam.min_quant[i]; + data.max_quant[i] = pEnc->mbParam.max_quant[i]; + } data.reference.csp = XVID_CSP_USER; data.reference.plane[0] = pEnc->reference->image.y; @@ -662,7 +698,7 @@ if (opt == XVID_PLG_BEFORE) { data.type = XVID_TYPE_AUTO; - data.quant = 2; + data.quant = 0; if ((pEnc->mbParam.plugin_flags & XVID_REQDQUANTS)) { data.dquant = pEnc->temp_dquants; @@ -672,7 +708,7 @@ /* todo: [vol,vop,motion]_flags*/ - } else { // XVID_PLG_AFTER + } else { /* XVID_PLG_AFTER */ if ((pEnc->mbParam.plugin_flags & XVID_REQORIGINAL)) { data.original.csp = XVID_CSP_USER; data.original.plane[0] = original->y; @@ -754,7 +790,7 @@ /* copy modified values back into frame*/ if (opt == XVID_PLG_BEFORE) { *type = data.type; - *quant = data.quant; + *quant = data.quant > 0 ? data.quant : 2; /* default */ if ((pEnc->mbParam.plugin_flags & XVID_REQDQUANTS)) { for (j=0; jmbParam.mb_height; j++) @@ -896,7 +932,7 @@ { if (pEnc->bframenum_head < pEnc->bframenum_tail) { - DPRINTF(DPRINTF_DEBUG,"*** BFRAME (flush) bf: head=%i tail=%i queue: head=%i tail=%i size=%i", + DPRINTF(XVID_DEBUG_DEBUG,"*** BFRAME (flush) bf: head=%i tail=%i queue: head=%i tail=%i size=%i\n", pEnc->bframenum_head, pEnc->bframenum_tail, pEnc->queue_head, pEnc->queue_tail, pEnc->queue_size); @@ -923,7 +959,7 @@ int tmp; int bits; - DPRINTF(DPRINTF_DEBUG,"*** EMPTY bf: head=%i tail=%i queue: head=%i tail=%i size=%i", + DPRINTF(XVID_DEBUG_DEBUG,"*** EMPTY bf: head=%i tail=%i queue: head=%i tail=%i size=%i\n", pEnc->bframenum_head, pEnc->bframenum_tail, pEnc->queue_head, pEnc->queue_tail, pEnc->queue_size); @@ -961,13 +997,16 @@ if (xFrame->input.csp == XVID_CSP_NULL) /* no futher input */ { + DPRINTF(XVID_DEBUG_DEBUG,"*** FINISH bf: head=%i tail=%i queue: head=%i tail=%i size=%i\n", + pEnc->bframenum_head, pEnc->bframenum_tail, + pEnc->queue_head, pEnc->queue_tail, pEnc->queue_size); + if (!(pEnc->mbParam.global_flags & XVID_GLOBAL_PACKED) && pEnc->mbParam.max_bframes > 0) { call_plugins(pEnc, pEnc->current, &pEnc->sOriginal, XVID_PLG_AFTER, 0, 0, stats); } /* if the very last frame is to be b-vop, we must change it to a p-vop */ - if (pEnc->bframenum_tail > 0) - { + if (pEnc->bframenum_tail > 0) { SWAP(FRAMEINFO*, pEnc->current, pEnc->reference); pEnc->bframenum_tail--; @@ -981,10 +1020,21 @@ pEnc->mbParam.edged_width, pEnc->mbParam.height); } - FrameCodeP(pEnc, &bs, 1, 0); + DPRINTF(XVID_DEBUG_DEBUG,"*** PFRAME bf: head=%i tail=%i queue: head=%i tail=%i size=%i\n", + pEnc->bframenum_head, pEnc->bframenum_tail, + pEnc->queue_head, pEnc->queue_tail, pEnc->queue_size); - goto done_flush; - } + FrameCodeP(pEnc, &bs, 1, 0); + + + if ((pEnc->mbParam.global_flags & XVID_GLOBAL_PACKED) && pEnc->bframenum_tail==0) { + call_plugins(pEnc, pEnc->current, &pEnc->sOriginal, XVID_PLG_AFTER, 0, 0, stats); + }else{ + pEnc->flush_bframes = 1; + goto done; + } + } + DPRINTF(XVID_DEBUG_DEBUG, "*** END\n"); emms(); return XVID_ERR_END; /* end of stream reached */ @@ -992,10 +1042,10 @@ goto done; /* nothing to encode yet; encoder lag */ } - // the current FRAME becomes the reference + /* the current FRAME becomes the reference */ SWAP(FRAMEINFO*, pEnc->current, pEnc->reference); - // remove frame from encoding-queue (head), and move it into the current + /* remove frame from encoding-queue (head), and move it into the current */ image_swap(&pEnc->current->image, &pEnc->queue[pEnc->queue_head].image); frame = &pEnc->queue[pEnc->queue_head].frame; pEnc->queue_head = (pEnc->queue_head + 1) % (pEnc->mbParam.max_bframes+1); @@ -1024,14 +1074,11 @@ * frame type & quant selection * %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */ - call_plugins(pEnc, pEnc->current, NULL, XVID_PLG_BEFORE, &type, &pEnc->current->quant, stats); - - if (frame->type > 0) - type = frame->type; - - if (frame->quant > 0) - pEnc->current->quant = frame->quant; + type = frame->type; + pEnc->current->quant = frame->quant; + call_plugins(pEnc, pEnc->current, NULL, XVID_PLG_BEFORE, &type, &pEnc->current->quant, stats); + if (type > 0){ /* XVID_TYPE_?VOP */ type = type2coding(type); /* convert XVID_TYPE_?VOP to bitstream coding type */ } else{ /* XVID_TYPE_AUTO */ @@ -1042,20 +1089,12 @@ type = MEanalysis(&pEnc->reference->image, pEnc->current, &pEnc->mbParam, pEnc->mbParam.iMaxKeyInterval, pEnc->iFrameNum, pEnc->bframenum_tail, xFrame->bframe_threshold); - - if (type == B_VOP && !(pEnc->current->vop_flags & XVID_VOP_DYNAMIC_BFRAMES)) { - type = P_VOP; /* disable dynamic bframes */ - } } } /* bframes buffer overflow check */ - if (type != I_VOP) { - if (pEnc->bframenum_tail >= pEnc->mbParam.max_bframes) { - type = P_VOP; - }else{ - type = B_VOP; - } + if (type == B_VOP && pEnc->bframenum_tail >= pEnc->mbParam.max_bframes) { + type = P_VOP; } pEnc->iFrameNum++; @@ -1087,7 +1126,7 @@ 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", + DPRINTF(XVID_DEBUG_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); @@ -1100,8 +1139,13 @@ goto repeat; } + + DPRINTF(XVID_DEBUG_DEBUG,"*** XXXXXX bf: head=%i tail=%i queue: head=%i tail=%i size=%i\n", + pEnc->bframenum_head, pEnc->bframenum_tail, + pEnc->queue_head, pEnc->queue_tail, pEnc->queue_size); + /* for unpacked bframes, output the stats for the last encoded frame */ - if (!(pEnc->mbParam.global_flags & XVID_GLOBAL_PACKED) && pEnc->bframenum_tail > 0) + if (!(pEnc->mbParam.global_flags & XVID_GLOBAL_PACKED) && pEnc->mbParam.max_bframes > 0) { if (pEnc->current->stamp > 0) { call_plugins(pEnc, pEnc->reference, &pEnc->sOriginal, XVID_PLG_AFTER, 0, 0, stats); @@ -1117,8 +1161,8 @@ if (type == I_VOP && (pEnc->mbParam.global_flags & XVID_GLOBAL_CLOSED_GOP) && pEnc->bframenum_tail > 0) { - // place this frame back on the encoding-queue (head) - // we will deal with it next time + /* place this frame back on the encoding-queue (head) */ + /* we will deal with it next time */ dec_frame_num(pEnc); pEnc->iFrameNum--; @@ -1126,7 +1170,7 @@ pEnc->queue_size++; image_swap(&pEnc->current->image, &pEnc->queue[pEnc->queue_head].image); - // grab the last frame from the bframe-queue + /* grab the last frame from the bframe-queue */ pEnc->bframenum_tail--; SWAP(FRAMEINFO*, pEnc->current, pEnc->bframes[pEnc->bframenum_tail]); @@ -1147,7 +1191,7 @@ if (type == I_VOP) { - DPRINTF(DPRINTF_DEBUG,"*** IFRAME bf: head=%i tail=%i queue: head=%i tail=%i size=%i", + DPRINTF(XVID_DEBUG_DEBUG,"*** IFRAME bf: head=%i tail=%i queue: head=%i tail=%i size=%i\n", pEnc->bframenum_head, pEnc->bframenum_tail, pEnc->queue_head, pEnc->queue_tail, pEnc->queue_size); @@ -1188,9 +1232,9 @@ * encode this frame as an p-vop * %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */ - } else { // (type == P_VOP || type == S_VOP) + } else { /* (type == P_VOP || type == S_VOP) */ - DPRINTF(DPRINTF_DEBUG,"*** PFRAME bf: head=%i tail=%i queue: head=%i tail=%i size=%i", + DPRINTF(XVID_DEBUG_DEBUG,"*** PFRAME bf: head=%i tail=%i queue: head=%i tail=%i size=%i\n", pEnc->bframenum_head, pEnc->bframenum_tail, pEnc->queue_head, pEnc->queue_tail, pEnc->queue_size); @@ -1215,13 +1259,13 @@ pEnc->flush_bframes = 1; - /* packed & queued_bframes: dont bother outputting stats, we do so after the flush */ + /* packed & queued_bframes: dont bother outputting stats here, we do so after the flush */ if ((pEnc->mbParam.global_flags & XVID_GLOBAL_PACKED) && pEnc->bframenum_tail > 0) { goto repeat; } - /* packed or no-bframes: output stats */ - if ((pEnc->mbParam.global_flags & XVID_GLOBAL_PACKED) || pEnc->mbParam.max_bframes == 0) { + /* packed or no-bframes or no-bframes-queued: output stats */ + if ((pEnc->mbParam.global_flags & XVID_GLOBAL_PACKED) || pEnc->mbParam.max_bframes == 0 ) { call_plugins(pEnc, pEnc->current, &pEnc->sOriginal, XVID_PLG_AFTER, 0, 0, stats); } @@ -1419,7 +1463,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->quarterpel = pEnc->mbParam.m_quarterpel; */ pEnc->current->fcode = pEnc->mbParam.m_fcode; if (!force_inter) @@ -1649,12 +1693,12 @@ VECTOR predMV = get_qpmv2(pEnc->current->mbs, pEnc->mbParam.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(DPRINTF_MV,"mv_diff (%i,%i) pred (%i,%i) result (%i,%i)", pMB->pmvs[0].x, pMB->pmvs[0].y, predMV.x, predMV.y, pMB->mvs[0].x, pMB->mvs[0].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(pEnc->current->mbs, pEnc->mbParam.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(DPRINTF_MV,"mv_diff (%i,%i) pred (%i,%i) result (%i,%i)", pMB->pmvs[0].x, pMB->pmvs[0].y, predMV.x, predMV.y, pMB->mvs[0].x, pMB->mvs[0].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); } @@ -1666,12 +1710,12 @@ VECTOR predMV = get_qpmv2(pEnc->current->mbs, pEnc->mbParam.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(DPRINTF_MV,"mv_diff (%i,%i) pred (%i,%i) result (%i,%i)", pMB->pmvs[k].x, pMB->pmvs[k].y, predMV.x, predMV.y, pMB->mvs[k].x, pMB->mvs[k].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(pEnc->current->mbs, pEnc->mbParam.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(DPRINTF_MV,"mv_diff (%i,%i) pred (%i,%i) result (%i,%i)", pMB->pmvs[k].x, pMB->pmvs[k].y, predMV.x, predMV.y, pMB->mvs[k].x, pMB->mvs[k].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); } } @@ -1721,7 +1765,9 @@ pEnc->fMvPrevSigma = fSigma; /* frame drop code */ - DPRINTF(DPRINTF_DEBUG, "kmu %i %i %i", pEnc->current->sStat.kblks, pEnc->current->sStat.mblks, pEnc->current->sStat.ublks); +#if 0 + DPRINTF(XVID_DEBUG_DEBUG, "kmu %i %i %i\n", pEnc->current->sStat.kblks, pEnc->current->sStat.mblks, pEnc->current->sStat.ublks); +#endif if (pEnc->current->sStat.kblks + pEnc->current->sStat.mblks < (pEnc->mbParam.frame_drop_ratio * mb_width * mb_height) / 100) { @@ -1737,7 +1783,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->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); @@ -1803,7 +1849,7 @@ } #endif - //frame->quarterpel = pEnc->mbParam.m_quarterpel; + /* frame->quarterpel = pEnc->mbParam.m_quarterpel; */ /* forward */ image_setedges(f_ref, pEnc->mbParam.edged_width,