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) |