Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2276036
  • 博文数量: 668
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 8588
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-29 19:22
文章分类

全部博文(668)

文章存档

2011年(1)

2010年(2)

2009年(273)

2008年(392)

分类:

2009-08-14 10:49:58

2)XviD编码一帧图像

对输入的一帧编码图像,根据程序判定或用户强制类型进行编码。编码器返回编码后的码流和长度及编码信息的统计。

函数enc_encode()流程如图14-3所示。

 
图14-3  enc_encode()流程图
根据该流程,具体代码如下。
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来实现真正的图像编码。

阅读(729) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~