📄 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: encoder.c,v 1.130 2007/02/08 13:10:24 Isibaar Exp $
*
****************************************************************************/
#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"
# include "motion/motion_smp.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 int
gcd(int a, int b)
{
int r ;
if (b > a) {
r = a;
a = b;
b = r;
}
while ((r = a % b)) {
a = b;
b = r;
}
return b;
}
static void
simplify_time(int *inc, int *base)
{
/* common factor */
const int s = gcd(*inc, *base);
*inc /= s;
*base /= s;
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 = (unsigned int)(((float)*biggest)/div);
*other = (unsigned int)(((float)*other)/div);
}
}
int
enc_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((int*)&pEnc->mbParam.fincr, (int*)&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(NULL, XVID_PLG_INFO, &pinfo, NULL) >= 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(NULL, 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;
}
/* temp lambdas */
if (pEnc->mbParam.plugin_flags & XVID_REQLAMBDA) {
pEnc->temp_lambda = (float *) xvid_malloc(pEnc->mbParam.mb_width *
pEnc->mbParam.mb_height * 6 * sizeof(float), CACHE_LINE);
if (pEnc->temp_lambda == 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -