int enc_encode(Encoder * pEnc, xvid_enc_frame_t
* xFrame, xvid_enc_stats_t * stats)
{
xvid_enc_frame_t * frame;
int type;
Bitstream bs; //存储码流
xFrame->out_flags = 0;
//初始化码流指针,以便于存储编码后的码流
BitstreamInit(&bs, xFrame->bitstream, 0);
//图像颜色空间为I420,即YUV的比例是4 2 0(或4 1 1)
if (xFrame->input.csp != XVID_CSP_NULL)
{
q = &pEnc->queue[0];
//读入图像帧到编码器的序列组中,input.plane => q->image
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, 0))
{
return XVID_ERR_FORMAT; //图像格式错误
}
q->frame = *xFrame;
pEnc->queue_tail = 0;
pEnc->queue_size++;
}
/*----------分析图像编码队列-------- */
if (pEnc->queue_size == 0){ /*队列为空*/
if (xFrame->input.csp == XVID_CSP_NULL) /*没有图像继续输入*/
return XVID_ERR_END; /*编码完毕,没有图像输出*/
goto done; /*没有图像编码;编码器延迟*/
}
SWAP(FRAMEINFO*, pEnc->current, pEnc->reference);
/*交换两图像的指针*/
image_swap(&pEnc->current->image, &pEnc->queue[0].
image); /*从序列组中读入一帧到
编码器中*/
frame = &pEnc->queue[0].frame;
pEnc->queue_head = 0;
pEnc->queue_size--;
/*----------初始化编码器的当前帧编码参数----------*/
pEnc->current->fincr=pEnc->mbParam.fincr>0?pEnc->
mbParam.fincr:frame->fincr;
inc_frame_num(pEnc);
/*修改时间戳、编码计数器*/
pEnc->current->vol_flags = frame->vol_flags; /*获取输入的VOL标志*/
pEnc->current->vop_flags = frame->vop_flags; /*获取输入的VOP标志*/
pEnc->current->motion_flags = frame->motion; /*获取输入的Motion标志*/
pEnc->current->fcode = pEnc->mbParam.m_fcode; /*获取ME的搜索窗口*/
/*----------选择编码帧类型和量化--------------*/
type = frame->type;
pEnc->current->quant = frame->quant;
if (type > 0){
type = type2coding(type);
} else{ /* XVID_TYPE_AUTO */
if (pEnc->iFrameNum == 0 || (pEnc->mbParam.iMaxKeyInterval > 0
&& pEnc->iFrameNum >= pEnc->mbParam.iMaxKeyInterval))
{
pEnc->iFrameNum = 0;
type = I_VOP; //强制编码类型I帧编码
}else{
type = P _VOP; //强制编码类型P帧编码
}
}
if (type != I_VOP)
pEnc->current->vol_flags = pEnc->mbParam.vol_flags;
/*编码器的编码帧计数*/
pEnc->iFrameNum++;
if (type == I_VOP) {
pEnc->iFrameNum = 1;
pEnc->mbParam.vol_flags = pEnc->current->
vol_flags; /*更新I_VOP的VOL标志*/
FrameCodeI(pEnc, &bs); /*图像为I帧编码 */
xFrame->out_flags |= XVID_KEYFRAME;
} else { /* (type == P_VOP || type == S_VOP) */
FrameCodeP(pEnc, &bs); /*图像为P帧编码 */
}
/*为统计编码器的各个参数,保存当前帧的编码参数:编码类型、量化步长、*/
/*码流长度、被编码宏块和没有编码的宏块数目等 */
#if 1
stats->type = pEnc->current->coding_type+1; //帧编码类型:I/P/B
stats->quant = pEnc->current->quant; //量化步长
stats->vol_flags = pEnc->current->vol_flags; //VOL标志
stats->vop_flags = pEnc->current->vop_flags; //VOP标志
stats->length = pEnc->current->length; //当前帧编码后的码流长度
stats->kblks = pEnc->current->sStat.kblks; //以intra模式编码的宏块数目
stats->mblks = pEnc->current->sStat.mblks; //以inter模式编码的宏块数目
stats->ublks = pEnc->current->sStat.ublks; //未编码的宏块数目
#endif
done:
return BitstreamLength(&bs); /*编码完毕,计算压缩后的码流长度*/
}
上述代码实现对传入的一帧图像的编码,编码方式可以是外部强制定义,也可以根据I帧间隔计算当前帧的编码类型。从上述代码分析可知,XviD的MPEG-4 SP编码算法有2个函数FrameCodeI和FrameCodeP来实现真正的图像编码。