📄 encoder.c
字号:
data.stats.hlength = frame->length - (frame->sStat.iTextBits / 8);
data.stats.kblks = frame->sStat.kblks;
data.stats.mblks = frame->sStat.mblks;
data.stats.ublks = frame->sStat.ublks;
data.stats.sse_y = data.sse_y;
data.stats.sse_u = data.sse_u;
data.stats.sse_v = data.sse_v;
if (stats)
*stats = data.stats;
}
/* call plugins */
for (i=0; i<(unsigned int)pEnc->num_plugins;i++) {
emms();
if (pEnc->plugins[i].func) {
if (pEnc->plugins[i].func(pEnc->plugins[i].param, opt, &data, NULL) < 0) {
continue;
}
}
}
emms();
/* copy modified values back into frame*/
if (opt == XVID_PLG_BEFORE) {
*type = data.type;
*quant = data.quant > 0 ? data.quant : 2; /* default */
frame->vol_flags = data.vol_flags;
frame->vop_flags = data.vop_flags;
frame->motion_flags = data.motion_flags;
} else if (opt == XVID_PLG_FRAME) {
if ((pEnc->mbParam.plugin_flags & XVID_REQDQUANTS)) {
for (j=0; j<pEnc->mbParam.mb_height; j++)
for (i=0; i<pEnc->mbParam.mb_width; i++) {
frame->mbs[j*pEnc->mbParam.mb_width + i].dquant = data.dquant[j*data.mb_width + i];
}
} else {
for (j=0; j<pEnc->mbParam.mb_height; j++)
for (i=0; i<pEnc->mbParam.mb_width; i++) {
frame->mbs[j*pEnc->mbParam.mb_width + i].dquant = 0;
}
}
if (pEnc->mbParam.plugin_flags & XVID_REQLAMBDA) {
for (j = 0; j < pEnc->mbParam.mb_height; j++)
for (i = 0; i < pEnc->mbParam.mb_width; i++)
for (k = 0; k < 6; k++) {
frame->mbs[j*pEnc->mbParam.mb_width + i].lambda[k] =
(int) ((float)(1<<LAMBDA_EXP) * data.lambda[6 * (j * data.mb_width + i) + k]);
}
} else {
for (j = 0; j<pEnc->mbParam.mb_height; j++)
for (i = 0; i<pEnc->mbParam.mb_width; i++)
for (k = 0; k < 6; k++) {
frame->mbs[j*pEnc->mbParam.mb_width + i].lambda[k] = 1<<LAMBDA_EXP;
}
}
frame->mbs[0].quant = data.quant; /* FRAME will not affect the quant in stats */
}
}
static __inline void inc_frame_num(Encoder * pEnc)
{
pEnc->current->frame_num = pEnc->m_framenum;
pEnc->current->stamp = pEnc->mbParam.m_stamp; /* first frame is zero */
pEnc->mbParam.m_stamp += pEnc->current->fincr;
pEnc->m_framenum++; /* debug ticker */
}
static __inline void dec_frame_num(Encoder * pEnc)
{
pEnc->mbParam.m_stamp -= pEnc->mbParam.fincr;
pEnc->m_framenum--; /* debug ticker */
}
static __inline void
MBSetDquant(MACROBLOCK * pMB, int x, int y, MBParam * mbParam)
{
if (pMB->cbp == 0) {
/* we want to code dquant but the quantizer value will not be used yet
let's find out if we can postpone dquant to next MB
*/
if (x == mbParam->mb_width-1 && y == mbParam->mb_height-1) {
pMB->dquant = 0; /* it's the last MB of all, the easiest case */
return;
} else {
MACROBLOCK * next = pMB + 1;
const MACROBLOCK * prev = pMB - 1;
if (next->mode != MODE_INTER4V && next->mode != MODE_NOT_CODED)
/* mode allows dquant change in the future */
if (abs(next->quant - prev->quant) <= 2) {
/* quant change is not out of range */
pMB->quant = prev->quant;
pMB->dquant = 0;
next->dquant = next->quant - prev->quant;
return;
}
}
}
/* couldn't skip this dquant */
pMB->mode = MODE_INTER_Q;
}
static __inline void
set_timecodes(FRAMEINFO* pCur,FRAMEINFO *pRef, int32_t time_base)
{
pCur->ticks = (int32_t)pCur->stamp % time_base;
pCur->seconds = ((int32_t)pCur->stamp / time_base) - ((int32_t)pRef->stamp / time_base) ;
#if 0 /* HEAVY DEBUG OUTPUT */
fprintf(stderr,"WriteVop: %d - %d \n",
((int32_t)pCur->stamp / time_base), ((int32_t)pRef->stamp / time_base));
fprintf(stderr,"set_timecodes: VOP %1d stamp=%lld ref_stamp=%lld base=%d\n",
pCur->coding_type, pCur->stamp, pRef->stamp, time_base);
fprintf(stderr,"set_timecodes: VOP %1d seconds=%d ticks=%d (ref-sec=%d ref-tick=%d)\n",
pCur->coding_type, pCur->seconds, pCur->ticks, pRef->seconds, pRef->ticks);
#endif
}
static void
simplify_par(int *par_width, int *par_height)
{
int _par_width = (!*par_width) ? 1 : (*par_width<0) ? -*par_width: *par_width;
int _par_height = (!*par_height) ? 1 : (*par_height<0) ? -*par_height: *par_height;
int divisor = gcd(_par_width, _par_height);
_par_width /= divisor;
_par_height /= divisor;
/* 2^8 precision maximum */
if (_par_width>255 || _par_height>255) {
float div;
emms();
if (_par_width>_par_height)
div = (float)_par_width/255;
else
div = (float)_par_height/255;
_par_width = (int)((float)_par_width/div);
_par_height = (int)((float)_par_height/div);
}
*par_width = _par_width;
*par_height = _par_height;
return;
}
/*****************************************************************************
* IPB frame encoder entry point
*
* Returned values :
* - >0 - output bytes
* - 0 - no output
* - XVID_ERR_VERSION - wrong version passed to core
* - XVID_ERR_END - End of stream reached before end of coding
* - XVID_ERR_FORMAT - the image subsystem reported the image had a wrong
* format
****************************************************************************/
int
enc_encode(Encoder * pEnc,
xvid_enc_frame_t * xFrame,
xvid_enc_stats_t * stats)
{
xvid_enc_frame_t * frame;
int type;
Bitstream bs;
if (XVID_VERSION_MAJOR(xFrame->version) != 1 || (stats && XVID_VERSION_MAJOR(stats->version) != 1)) /* v1.x.x */
return XVID_ERR_VERSION;
xFrame->out_flags = 0;
start_global_timer();
BitstreamInit(&bs, xFrame->bitstream, 0);
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
* enqueue image to the encoding-queue
* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
if (xFrame->input.csp != XVID_CSP_NULL)
{
QUEUEINFO * q = &pEnc->queue[pEnc->queue_tail];
start_timer();
if (image_input
(&q->image, pEnc->mbParam.width, pEnc->mbParam.height,
pEnc->mbParam.edged_width, (uint8_t**)xFrame->input.plane, xFrame->input.stride,
xFrame->input.csp, xFrame->vol_flags & XVID_VOL_INTERLACING))
{
emms();
return XVID_ERR_FORMAT;
}
stop_conv_timer();
if ((xFrame->vop_flags & XVID_VOP_CHROMAOPT)) {
image_chroma_optimize(&q->image,
pEnc->mbParam.width, pEnc->mbParam.height, pEnc->mbParam.edged_width);
}
q->frame = *xFrame;
if (xFrame->quant_intra_matrix)
{
memcpy(q->quant_intra_matrix, xFrame->quant_intra_matrix, 64*sizeof(unsigned char));
q->frame.quant_intra_matrix = q->quant_intra_matrix;
}
if (xFrame->quant_inter_matrix)
{
memcpy(q->quant_inter_matrix, xFrame->quant_inter_matrix, 64*sizeof(unsigned char));
q->frame.quant_inter_matrix = q->quant_inter_matrix;
}
pEnc->queue_tail = (pEnc->queue_tail + 1) % (pEnc->mbParam.max_bframes+1);
pEnc->queue_size++;
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
* bframe flush code
* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
repeat:
if (pEnc->flush_bframes)
{
if (pEnc->bframenum_head < pEnc->bframenum_tail) {
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);
if ((pEnc->mbParam.plugin_flags & XVID_REQORIGINAL)) {
image_copy(&pEnc->sOriginal2, &pEnc->bframes[pEnc->bframenum_head]->image,
pEnc->mbParam.edged_width, pEnc->mbParam.height);
}
FrameCodeB(pEnc, pEnc->bframes[pEnc->bframenum_head], &bs);
call_plugins(pEnc, pEnc->bframes[pEnc->bframenum_head], &pEnc->sOriginal2, XVID_PLG_AFTER, NULL, NULL, stats);
pEnc->bframenum_head++;
goto done;
}
/* write an empty marker to the bitstream.
for divx5 decoder compatibility, this marker must consist
of a not-coded p-vop, with a time_base of zero, and time_increment
indentical to the future-referece frame.
*/
if ((pEnc->mbParam.global_flags & XVID_GLOBAL_PACKED && pEnc->bframenum_tail > 0)) {
int tmp;
int bits;
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);
bits = BitstreamPos(&bs);
tmp = pEnc->current->seconds;
pEnc->current->seconds = 0; /* force time_base = 0 */
BitstreamWriteVopHeader(&bs, &pEnc->mbParam, pEnc->current, 0, pEnc->current->quant);
BitstreamPad(&bs);
pEnc->current->seconds = tmp;
/* add the not-coded length to the reference frame size */
pEnc->current->length += (BitstreamPos(&bs) - bits) / 8;
call_plugins(pEnc, pEnc->current, &pEnc->sOriginal, XVID_PLG_AFTER, NULL, NULL, stats);
/* flush complete: reset counters */
pEnc->flush_bframes = 0;
pEnc->bframenum_head = pEnc->bframenum_tail = 0;
goto done;
}
/* flush complete: reset counters */
pEnc->flush_bframes = 0;
pEnc->bframenum_head = pEnc->bframenum_tail = 0;
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
* dequeue frame from the encoding queue
* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
if (pEnc->queue_size == 0) /* empty */
{
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, NULL, NULL, stats);
}
/* if the very last frame is to be b-vop, we must change it to a p-vop */
if (pEnc->bframenum_tail > 0) {
SWAP(FRAMEINFO*, pEnc->current, pEnc->reference);
pEnc->bframenum_tail--;
SWAP(FRAMEINFO*, pEnc->current, pEnc->bframes[pEnc->bframenum_tail]);
/* convert B-VOP to P-VOP */
pEnc->current->quant = 100*pEnc->current->quant - pEnc->mbParam.bquant_offset;
pEnc->current->quant += pEnc->mbParam.bquant_ratio - 1; /* to avoid rouding issues */
pEnc->current->quant /= pEnc->mbParam.bquant_ratio;
if ((pEnc->mbParam.plugin_flags & XVID_REQORIGINAL)) {
image_copy(&pEnc->sOriginal, &pEnc->current->image,
pEnc->mbParam.edged_width, pEnc->mbParam.height);
}
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);
pEnc->mbParam.frame_drop_ratio = -1; /* it must be a coded vop */
FrameCodeP(pEnc, &bs);
if ((pEnc->mbParam.global_flags & XVID_GLOBAL_PACKED) && pEnc->bframenum_tail==0) {
call_plugins(pEnc, pEnc->current, &pEnc->sOriginal, XVID_PLG_AFTER, NULL, NULL, stats);
}else{
pEnc->flush_bframes = 1;
goto done;
}
}
DPRINTF(XVID_DEBUG_DEBUG, "*** END\n");
emms();
return XVID_ERR_END; /* end of stream reached */
}
goto done; /* nothing to encode yet; encoder lag */
}
/* the current FRAME becomes the reference */
SWAP(FRAMEINFO*, pEnc->current, pEnc->reference);
/* 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);
pEnc->queue_size--;
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
* init pEnc->current fields
* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
pEnc->current->fincr = pEnc->mbParam.fincr>0 ? pEnc->mbParam.fincr : frame->fincr;
inc_frame_num(pEnc);
pEnc->current->vol_flags = frame->vol_flags;
pEnc->current->vop_flags = frame->vop_flags;
pEnc->current->motion_flags = frame->motion;
pEnc->current->fcode = pEnc->mbParam.m_fcode;
pEnc->current->bcode = pEnc->mbParam.m_fcode;
if ((xFrame->vop_flags & XVID_VOP_CHROMAOPT)) {
image_chroma_optimize(&pEnc->current->image,
pEnc->mbParam.width, pEnc->mbParam.height, pEnc->mbParam.edged_width);
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
* frame type & quant selection
* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
type = frame->type;
pEnc->current->quant = frame->quant;
call_plugins(pEnc, pEnc->current, NULL, XVID_PLG_BEFORE, &type, (int*)&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 */
if (pEnc->iFrameNum == 0 || (pEnc->mbParam.iMaxKeyInterval > 0 && pEnc->iFrameNum >= pEnc->mbParam.iMaxKeyInterval)){
pEnc->iFrameNum = 0;
type = I_VOP;
}else{
type = MEanalysis(&pEnc->reference->image, pEnc->current,
&pEnc->mbParam, pEnc->mbParam.iMaxKeyInterval,
pEnc->iFrameNum, pEnc->bframenum_tail, xFrame->bframe_threshold,
(pEnc->bframes) ? pEnc->bframes[pEnc->bframenum_head]->mbs: NULL);
}
}
if (type != I_VOP)
pEnc->current->vol_flags = pEnc->mbParam.vol_flags; /* don't allow VOL changes here */
/* bframes buffer overflow check */
if (type == B_VOP && pEnc->bframenum_tail >= pEnc->mbParam.max_bframes) {
type = P_VOP;
}
pEnc->iFrameNum++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -