📄 encoder.c
字号:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "encoder.h"
#include "prediction/mbprediction.h"
#include "global.h"
#include "utils/timer.h"
#include "image/image.h"
#include "bitstream/cbp.h"
#include "utils/mbfunctions.h"
#include "bitstream/bitstream.h"
#include "bitstream/mbcoding.h"
#include "utils/ratecontrol.h"
#include "utils/emms.h"
#include "bitstream/mbcoding.h"
#include "quant/adapt_quant.h"
#include "quant/quant_matrix.h"
#include "utils/mem_align.h"
#define ENC_CHECK(X) if(!(X)) return XVID_ERR_FORMAT
#ifdef MPEG4IP
static int FrameCodeI(Encoder * pEnc, Bitstream * bs, uint32_t *pBits, bool vol_header);
#else
static int FrameCodeI(Encoder * pEnc, Bitstream * bs, uint32_t *pBits);
#endif
static int FrameCodeP(Encoder * pEnc, Bitstream * bs, uint32_t *pBits, bool force_inter, bool vol_header);
static int DQtab[4] =
{
-1, -2, 1, 2
};
static int iDQtab[5] =
{
1, 0, NO_CHANGE, 2, 3
};
int encoder_create(XVID_ENC_PARAM * pParam)
{
Encoder *pEnc;
uint32_t i;
pParam->handle = NULL;
ENC_CHECK(pParam);
ENC_CHECK(pParam->width > 0 && pParam->width <= 1920);
ENC_CHECK(pParam->height > 0 && pParam->height <= 1280);
ENC_CHECK(!(pParam->width % 2));
ENC_CHECK(!(pParam->height % 2));
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)
i = pParam->fincr;
while (i > 1)
{
if (pParam->fincr % i == 0 && pParam->fbase % i == 0)
{
pParam->fincr /= i;
pParam->fbase /= i;
i = pParam->fincr;
continue;
}
i--;
}
if (pParam->fbase > 65535)
{
float div = (float)pParam->fbase / 65535;
pParam->fbase = (int)(pParam->fbase / div);
pParam->fincr = (int)(pParam->fincr / div);
}
if (pParam->bitrate <= 0)
pParam->bitrate = 900000;
if (pParam->rc_buffersize <= 0)
pParam->rc_buffersize = 16;
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)
return XVID_ERR_MEMORY;
/* Fill members of Encoder structure */
pEnc->mbParam.width = pParam->width;
pEnc->mbParam.height = pParam->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;
#ifdef MPEG4IP
pEnc->mbParam.fincr = pParam->fincr;
pEnc->mbParam.fbase = pParam->fbase;
pEnc->mbParam.time_inc_bits = 1;
while (pParam->fbase > (1 << pEnc->mbParam.time_inc_bits)) {
pEnc->mbParam.time_inc_bits++;
}
#endif
pEnc->sStat.fMvPrevSigma = -1;
/* Fill rate control parameters */
pEnc->mbParam.quant = 4;
pEnc->bitrate = pParam->bitrate;
pEnc->iFrameNum = 0;
pEnc->iMaxKeyInterval = pParam->max_key_interval;
/* try to allocate memory */
pEnc->sCurrent.y = pEnc->sCurrent.u = pEnc->sCurrent.v = NULL;
pEnc->sReference.y = pEnc->sReference.u = pEnc->sReference.v = NULL;
pEnc->vInterH.y = pEnc->vInterH.u = pEnc->vInterH.v = NULL;
pEnc->vInterV.y = pEnc->vInterV.u = pEnc->vInterV.v = NULL;
pEnc->vInterVf.y = pEnc->vInterVf.u = pEnc->vInterVf.v = NULL;
pEnc->vInterHV.y = pEnc->vInterHV.u = pEnc->vInterHV.v = NULL;
pEnc->vInterHVf.y = pEnc->vInterHVf.u = pEnc->vInterHVf.v = NULL;
pEnc->pMBs = NULL;
if (image_create(&pEnc->sCurrent, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0 ||
image_create(&pEnc->sReference, 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_create(&pEnc->sOriginal, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height) < 0 ||
#endif
(pEnc->pMBs = xvid_malloc(sizeof(MACROBLOCK) * pEnc->mbParam.mb_width * pEnc->mbParam.mb_height, CACHE_LINE)) == NULL)
{
image_destroy(&pEnc->sCurrent, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height);
image_destroy(&pEnc->sReference, 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 _DEBUG
image_destroy(&pEnc->sOriginal, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height);
#endif
if (pEnc)
{
xvid_free(pEnc);
}
return XVID_ERR_MEMORY;
}
// init macroblock array
for (i = 0; i < pEnc->mbParam.mb_width * pEnc->mbParam.mb_height; i++)
{
pEnc->pMBs[i].dquant = NO_CHANGE;
}
pParam->handle = (void *)pEnc;
if (pParam->bitrate)
{
RateControlInit(pParam->bitrate, pParam->rc_buffersize, pParam->fbase * 1000 / pParam->fincr,
pParam->max_quantizer, pParam->min_quantizer);
}
init_timer();
return XVID_ERR_OK;
}
int encoder_destroy(Encoder * pEnc)
{
ENC_CHECK(pEnc);
ENC_CHECK(pEnc->sCurrent.y);
ENC_CHECK(pEnc->sReference.y);
xvid_free(pEnc->pMBs);
image_destroy(&pEnc->sCurrent, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height);
image_destroy(&pEnc->sReference, 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 _DEBUG
image_destroy(&pEnc->sOriginal, pEnc->mbParam.edged_width, pEnc->mbParam.edged_height);
#endif
xvid_free(pEnc);
return XVID_ERR_OK;
}
int encoder_encode(Encoder * pEnc, XVID_ENC_FRAME * pFrame, XVID_ENC_STATS * pResult)
{
uint16_t x, y;
Bitstream bs;
uint32_t bits;
uint16_t write_vol_header = 0;
#ifdef _DEBUG
float psnr;
uint8_t temp[100];
#endif
start_global_timer();
ENC_CHECK(pEnc);
ENC_CHECK(pFrame);
ENC_CHECK(pFrame->bitstream);
#ifndef MPEG4IP
ENC_CHECK(pFrame->image);
#endif
pEnc->mbParam.global_flags = pFrame->general;
pEnc->mbParam.motion_flags = pFrame->motion;
pEnc->mbParam.hint = &pFrame->hint;
start_timer();
#ifdef MPEG4IP
if (pFrame->image == NULL
&& pFrame->colorspace == XVID_CSP_I420) {
ENC_CHECK(pFrame->image_y);
ENC_CHECK(pFrame->image_u);
ENC_CHECK(pFrame->image_v);
ENC_CHECK(pFrame->stride >= pEnc->mbParam.width);
if (yuv_input(&pEnc->sCurrent,
pEnc->mbParam.width,
pEnc->mbParam.height,
pEnc->mbParam.edged_width,
pFrame->image_y, pFrame->image_u, pFrame->image_v,
pFrame->stride,
pFrame->colorspace)) {
return XVID_ERR_FORMAT;
}
} else {
#endif
if (image_input(&pEnc->sCurrent, pEnc->mbParam.width, pEnc->mbParam.height,
pEnc->mbParam.edged_width, pFrame->image, pFrame->colorspace))
{
return XVID_ERR_FORMAT;
}
#ifdef MPEG4IP
}
#endif
stop_conv_timer();
EMMS();
#ifdef _DEBUG
image_copy(&pEnc->sOriginal, &pEnc->sCurrent, pEnc->mbParam.edged_width, pEnc->mbParam.height);
#endif
BitstreamInit(&bs, pFrame->bitstream, 0);
if (pFrame->quant == 0)
{
pEnc->mbParam.quant = RateControlGetQ(0);
}
else
{
pEnc->mbParam.quant = pFrame->quant;
}
if ((pEnc->mbParam.global_flags & XVID_LUMIMASKING) > 0)
{
int * temp_dquants = (int *) xvid_malloc(pEnc->mbParam.mb_width * pEnc->mbParam.mb_height * sizeof(int), CACHE_LINE);
pEnc->mbParam.quant = adaptive_quantization(pEnc->sCurrent.y,
pEnc->mbParam.width,
temp_dquants,
pEnc->mbParam.quant,
pEnc->mbParam.quant,
2*pEnc->mbParam.quant,
pEnc->mbParam.mb_width,
pEnc->mbParam.mb_height);
for (y = 0; y < pEnc->mbParam.mb_height; y++)
for (x = 0; x < pEnc->mbParam.mb_width; x++)
{
MACROBLOCK *pMB = &pEnc->pMBs[x + y * pEnc->mbParam.mb_width];
pMB->dquant = iDQtab[(temp_dquants[y * pEnc->mbParam.mb_width + x] + 2)];
}
xvid_free(temp_dquants);
}
if(pEnc->mbParam.global_flags & XVID_H263QUANT) {
if(pEnc->mbParam.quant_type != H263_QUANT)
write_vol_header = 1;
pEnc->mbParam.quant_type = H263_QUANT;
}
else if(pEnc->mbParam.global_flags & XVID_MPEGQUANT) {
int ret1, ret2;
ret1 = ret2 = 0;
if(pEnc->mbParam.quant_type != MPEG4_QUANT)
write_vol_header = 1;
pEnc->mbParam.quant_type = MPEG4_QUANT;
if ((pEnc->mbParam.global_flags & XVID_CUSTOM_QMATRIX) > 0) {
if(pFrame->quant_intra_matrix != NULL)
ret1 = set_intra_matrix(pFrame->quant_intra_matrix);
if(pFrame->quant_inter_matrix != NULL)
ret2 = set_inter_matrix(pFrame->quant_inter_matrix);
}
else {
ret1 = set_intra_matrix(get_default_intra_matrix());
ret2 = set_inter_matrix(get_default_inter_matrix());
}
if(write_vol_header == 0)
write_vol_header = ret1 | ret2;
}
#ifdef MPEG4IP
if (pEnc->iFrameNum == 0) {
BitstreamWriteVoshHeader(&bs);
write_vol_header = 1;
}
#endif
if (pFrame->intra < 0)
{
if ((pEnc->iFrameNum == 0) || ((pEnc->iMaxKeyInterval > 0)
&& (pEnc->iFrameNum >= pEnc->iMaxKeyInterval)))
#ifdef MPEG4IP
pFrame->intra = FrameCodeI(pEnc, &bs, &bits, write_vol_header);
#else
pFrame->intra = FrameCodeI(pEnc, &bs, &bits);
#endif
else
pFrame->intra = FrameCodeP(pEnc, &bs, &bits, 0, write_vol_header);
}
else
{
if (pFrame->intra == 1)
#ifdef MPEG4IP
pFrame->intra = FrameCodeI(pEnc, &bs, &bits, write_vol_header);
#else
pFrame->intra = FrameCodeI(pEnc, &bs, &bits);
#endif
else
pFrame->intra = FrameCodeP(pEnc, &bs, &bits, 1, write_vol_header);
}
BitstreamPutBits(&bs, 0xFFFF, 16);
BitstreamPutBits(&bs, 0xFFFF, 16);
BitstreamPad(&bs);
pFrame->length = BitstreamLength(&bs);
if (pResult)
{
pResult->quant = pEnc->mbParam.quant;
pResult->hlength = pFrame->length - (pEnc->sStat.iTextBits / 8);
pResult->kblks = pEnc->sStat.kblks;
pResult->mblks = pEnc->sStat.mblks;
pResult->ublks = pEnc->sStat.ublks;
#ifdef MPEG4IP
pResult->image_y = pEnc->sCurrent.y;
pResult->image_u = pEnc->sCurrent.u;
pResult->image_v = pEnc->sCurrent.v;
pResult->stride_y = pEnc->mbParam.edged_width;
pResult->stride_uv = pResult->stride_y / 2;
#endif
}
EMMS();
if (pFrame->quant == 0)
{
RateControlUpdate(pEnc->mbParam.quant, pFrame->length, pFrame->intra);
}
#ifdef _DEBUG
psnr = image_psnr(&pEnc->sOriginal, &pEnc->sCurrent, pEnc->mbParam.edged_width,
pEnc->mbParam.width, pEnc->mbParam.height);
sprintf(temp, "PSNR: %f\n", psnr);
DEBUG(temp);
#endif
pEnc->iFrameNum++;
image_swap(&pEnc->sCurrent, &pEnc->sReference);
stop_global_timer();
write_timer();
return XVID_ERR_OK;
}
static __inline void CodeIntraMB(Encoder *pEnc, MACROBLOCK *pMB) {
pMB->mode = MODE_INTRA;
if ((pEnc->mbParam.global_flags & XVID_LUMIMASKING) > 0) {
if(pMB->dquant != NO_CHANGE)
{
pMB->mode = MODE_INTRA_Q;
pEnc->mbParam.quant += DQtab[pMB->dquant];
if (pEnc->mbParam.quant > 31) pEnc->mbParam.quant = 31;
if (pEnc->mbParam.quant < 1) pEnc->mbParam.quant = 1;
}
}
pMB->quant = pEnc->mbParam.quant;
}
#define FCODEBITS 3
#define MODEBITS 5
static
void HintedMESet(Encoder * pEnc, int * intra)
{
HINTINFO * hint;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -