📄 encoder.c
字号:
/***************************************************************************** * * XVID MPEG-4 VIDEO CODEC * - Encoder main module - * * Copyright(C) 2002 Michael Militzer <isibaar@xvid.org> * 2002-2003 Peter Ross <pross@xvid.org> * 2002 Daniel Smith <danielsmith@astroboymail.com> * * 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 * (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 * 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 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ * ****************************************************************************/#include <stdlib.h>#include <stdio.h>#include <math.h>#include <string.h>#include "encoder.h"#include "prediction/mbprediction.h"#include "global.h"#include "utils/timer.h"#include "image/image.h"#include "image/font.h"#include "motion/sad.h"#include "motion/motion.h"#include "motion/gmc.h"#include "bitstream/cbp.h"#include "utils/mbfunctions.h"#include "bitstream/bitstream.h"#include "bitstream/mbcoding.h"#include "utils/emms.h"#include "bitstream/mbcoding.h"#include "quant/quant_matrix.h"#include "utils/mem_align.h"/***************************************************************************** * Local function prototypes ****************************************************************************/static int FrameCodeI(Encoder * pEnc, Bitstream * bs);static int FrameCodeP(Encoder * pEnc, Bitstream * bs);static void FrameCodeB(Encoder * pEnc, FRAMEINFO * frame, Bitstream * bs);/***************************************************************************** * Encoder creation * * This function creates an Encoder instance, it allocates all necessary * image buffers (reference, current and bframes) and initialize the internal * xvid encoder paremeters according to the XVID_ENC_PARAM input parameter. * * The code seems to be very long but is very basic, mainly memory allocation * and cleaning code. * * Returned values : * - 0 - no errors * - XVID_ERR_MEMORY - the libc could not allocate memory, the function * cleans the structure before exiting. * pParam->handle is also set to NULL. * ****************************************************************************//* * Simplify the "fincr/fbase" fraction*/static voidsimplify_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 (*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 = (int)(((float)*biggest)/div); *other = (int)(((float)*other)/div); }}intenc_create(xvid_enc_create_t * create){ Encoder *pEnc; int n; if (XVID_VERSION_MAJOR(create->version) != 1) /* v1.x.x */ return XVID_ERR_VERSION; if (create->width%2 || create->height%2) return XVID_ERR_FAIL; if (create->width<=0 || create->height<=0) return XVID_ERR_FAIL; /* allocate encoder struct */ pEnc = (Encoder *) xvid_malloc(sizeof(Encoder), CACHE_LINE); if (pEnc == NULL) return XVID_ERR_MEMORY; memset(pEnc, 0, sizeof(Encoder)); pEnc->mbParam.profile = create->profile; /* 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; pEnc->mbParam.height = create->height; 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; /* framerate */ 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); /* 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; n<pEnc->num_plugins;n++) { xvid_plg_create_t pcreate; xvid_plg_info_t pinfo; memset(&pinfo, 0, sizeof(xvid_plg_info_t)); pinfo.version = XVID_VERSION; if (create->plugins[n].func(0, XVID_PLG_INFO, &pinfo, 0) >= 0) { pEnc->mbParam.plugin_flags |= pinfo.flags; } 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.mb_width = pEnc->mbParam.mb_width; pcreate.mb_height = pEnc->mbParam.mb_height; pcreate.fincr = pEnc->mbParam.fincr; pcreate.fbase = pEnc->mbParam.fbase; pcreate.param = create->plugins[n].param; pEnc->plugins[n].func = NULL; /* disable plugins that fail */ if (create->plugins[n].func(0, XVID_PLG_CREATE, &pcreate, &pEnc->plugins[n].param) >= 0) { pEnc->plugins[n].func = create->plugins[n].func; } } if ((pEnc->mbParam.global_flags & XVID_GLOBAL_EXTRASTATS_ENABLE) || (pEnc->mbParam.plugin_flags & XVID_REQPSNR)) { pEnc->mbParam.plugin_flags |= XVID_REQORIGINAL; /* psnr calculation requires the original */ } /* temp dquants */ if ((pEnc->mbParam.plugin_flags & XVID_REQDQUANTS)) { pEnc->temp_dquants = (int *) xvid_malloc(pEnc->mbParam.mb_width * pEnc->mbParam.mb_height * sizeof(int), CACHE_LINE); if (pEnc->temp_dquants==NULL) goto xvid_err_memory1a; } /* bframes */ 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 ? (10 * (int)pEnc->mbParam.fbase) / (int)pEnc->mbParam.fincr : create->max_key_interval; /* allocate working frame-image 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; /* allocate macroblock memory */ 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 == NULL || pEnc->reference->mbs == NULL) goto xvid_err_memory2; /* allocate quant matrix memory */ pEnc->mbParam.mpeg_quant_matrices = xvid_malloc(sizeof(uint16_t) * 64 * 8, CACHE_LINE); if (pEnc->mbParam.mpeg_quant_matrices == NULL) goto xvid_err_memory2a; /* allocate interpolation image memory */ if ((pEnc->mbParam.plugin_flags & XVID_REQORIGINAL)) { image_null(&pEnc->sOriginal); image_null(&pEnc->sOriginal2); } image_null(&pEnc->f_refh); image_null(&pEnc->f_refv); image_null(&pEnc->f_refhv); image_null(&pEnc->current->image); image_null(&pEnc->reference->image); image_null(&pEnc->vInterH); image_null(&pEnc->vInterV); image_null(&pEnc->vInterHV); if ((pEnc->mbParam.plugin_flags & XVID_REQORIGINAL)) { if (image_create (&pEnc->sOriginal, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0) goto xvid_err_memory3; if (image_create (&pEnc->sOriginal2, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0) goto xvid_err_memory3; } 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; 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->vInterHV, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0) goto xvid_err_memory3;/* Create full bitplane for GMC, this might be wasteful */ if (image_create (&pEnc->vGMC, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0) goto xvid_err_memory3; /* init bframe image buffers */ pEnc->bframenum_head = 0; pEnc->bframenum_tail = 0; pEnc->flush_bframes = 0; pEnc->closed_bframenum = -1; /* B Frames specific init */ pEnc->bframes = NULL; if (pEnc->mbParam.max_bframes > 0) { 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->mbParam.max_bframes; n++) pEnc->bframes[n] = NULL; for (n = 0; n < pEnc->mbParam.max_bframes; n++) { 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; } } /* init incoming frame queue */ pEnc->queue_head = 0; pEnc->queue_tail = 0; pEnc->queue_size = 0; pEnc->queue = xvid_malloc((pEnc->mbParam.max_bframes+1) * sizeof(QUEUEINFO), CACHE_LINE); if (pEnc->queue == NULL) goto xvid_err_memory4; for (n = 0; n < pEnc->mbParam.max_bframes+1; n++) image_null(&pEnc->queue[n].image); for (n = 0; n < pEnc->mbParam.max_bframes+1; n++) { if (image_create (&pEnc->queue[n].image, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0) goto xvid_err_memory5; } /* timestamp stuff */ pEnc->mbParam.m_stamp = 0; pEnc->m_framenum = 0; pEnc->current->stamp = 0; pEnc->reference->stamp = 0; /* other stuff */ pEnc->iFrameNum = 0; pEnc->fMvPrevSigma = -1; create->handle = (void *) pEnc; init_timer(); init_mpeg_matrix(pEnc->mbParam.mpeg_quant_matrices); return 0; /* ok */ /* * We handle all XVID_ERR_MEMORY here, this makes the code lighter */ xvid_err_memory5: for (n = 0; n < pEnc->mbParam.max_bframes+1; n++) { image_destroy(&pEnc->queue[n].image, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); } xvid_free(pEnc->queue); xvid_err_memory4: if (pEnc->mbParam.max_bframes > 0) { int i; for (i = 0; i < pEnc->mbParam.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); } xvid_err_memory3: if ((pEnc->mbParam.plugin_flags & XVID_REQORIGINAL)) { image_destroy(&pEnc->sOriginal, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height); image_destroy(&pEnc->sOriginal2, 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); 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->vInterHV, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height);/* destroy GMC image */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -