⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vop_code.c

📁 MPEG4视频编解码内有divx(编码)
💻 C
字号:
//视频对象平面编码函数代码


#include "vop_code.h"
#include "mot_est_comp.h"
//#include "rc_q2.h"
#include "bitstream.h"

#include "rate_ctl.h"

#define SCENE_CHANGE_THREADHOLD 50
#define MB_RATIO_THREADHOLD 0.40

extern FILE *ftrace;

UInt  	BitstreamPutVopHeader (	Vop *vop,
			Float time,
			VolConfig *vol_config
	);
Void ImageRepetitivePadding(Image *image, Int edge);
Double compute_MAD(Vop *vop);


/***********************************************************CommentBegin******
函数功能:
实现视频对象平面中对象形状、纹理和运动的编码。并且,前提假设输入的视频对象平面是带边界的。
函数输入:
1)Vop* curr:指向当前待编码的视频对象平面的指针;
2)Vop* prev:指向本视频对象平面之前最后出现的视频对象平面的指针;
3)Vop* rec_prev:指向本视频对象平面之前最后已出现并编码的视频对象平面的指针;
4)Int enable_8x8_mv:8×8运动向量的标志;
5)Int intra_dcpred_disable:不允许内部DC频段预测的控制变量;
6)Float time:当前编码时间;
7)VolConfig* vol_config:视频对象层的设置信息。
函数输入/输出:
1)Vop* rec_curr:以编码视频对象平面;
2)Bitcount num_bits:比特统计结构。

 ***********************************************************CommentEnd********/

Void VopCode(Vop *curr, Vop *reference, Vop *reconstruct, Vop *error, Int enable_8x8_mv,
			Float time, VolConfig *vol_config)
{
	ImageF *mot_x=NULL, *mot_y=NULL;
	Image *MB_decisions=NULL;
	Int edge,f_code_for=1;
	Vop *error_vop=NULL;
	Int vop_quantizer;

	Float mad_P = 0., mad_I = 0.;
	Float IntraMBRatio = 1.;
	Int numberMB, i, IntraMB;

	edge = 0;
	f_code_for = curr->fcode_for;

	if (curr->prediction_type == P_VOP) 
	{
		/*进行运动估计和补偿*/
		MotionEstimationCompensation(curr, reference,
			enable_8x8_mv, edge ,f_code_for,
			reconstruct, &mad_P, &mot_x,&mot_y,&MB_decisions);

		/*计算处于帧内的宏块所占的百分比*/
		IntraMB = 0;
		numberMB = MB_decisions->x * MB_decisions->y;
		for (i = 0; i < numberMB; i ++)
			if (MB_decisions->f[i] == MBM_INTRA) IntraMB ++;
		IntraMBRatio = (float)IntraMB / (float)numberMB;

		#ifdef _RC_
		fprintf(ftrace, "ME with MAD : %f\n", mad_P);
		fprintf(ftrace, "%4.2f of the MBs are I-MBs.\n", IntraMBRatio);
		#endif
	}
	else
		mad_P = SCENE_CHANGE_THREADHOLD * 2;

	if ((mad_P < SCENE_CHANGE_THREADHOLD / 3) || 
		((mad_P < SCENE_CHANGE_THREADHOLD) && (IntraMBRatio < MB_RATIO_THREADHOLD)))
	{
		//容忍值未超过,继续进行P-VOP的编码
		curr->prediction_type = P_VOP;
		error->prediction_type = P_VOP;

		#ifdef _RC_
		fprintf(ftrace, "Coding mode : INTER\n");
		#endif

		vop_quantizer = RateCtlGetQ(mad_P);

		curr->quantizer = vop_quantizer;
		error->quantizer = vop_quantizer;

		#ifdef _RC_DEBUG_
		fprintf(stdout, "RC: >>>>> New quantizer= %d\n", vop_quantizer);
		#endif

		SubImage(curr->y_chan, reconstruct->y_chan, error->y_chan);
		SubImage(curr->u_chan, reconstruct->u_chan, error->u_chan);
		SubImage(curr->v_chan, reconstruct->v_chan, error->v_chan); 

		BitstreamPutVopHeader(curr,time,vol_config);

		VopShapeMotText(error, reconstruct, MB_decisions,
			mot_x, mot_y, f_code_for, 
			GetVopIntraACDCPredDisable(curr), reference,
			NULL/*运动纹理比特流数据*/);
	} else {
		//容忍值过大 
		//此时的编码模式应转为I-VOP模式
		curr->prediction_type = I_VOP;
		curr->rounding_type = 1;

		#ifdef _RC_
		fprintf(ftrace, "Coding mode : INTRA\n");
		#endif

		//上一次的容忍值是假设计算的,现在有必要重新计算容忍值
		//内部编码,可能实际的差分值不是编码的大系数
		if (mad_I == 0.) mad_I = (Float) compute_MAD(curr);

		vop_quantizer = RateCtlGetQ(mad_I);

		curr->intra_quantizer = vop_quantizer;
		curr->rounding_type = 1;

		BitstreamPutVopHeader(curr,time,vol_config);

		/*以内部模式进行纹理编码*/
		VopCodeShapeTextIntraCom(curr,
			reference,
			NULL/*纹理编码数据*/
		);
	} 


	if (MB_decisions) FreeImage(MB_decisions);
	if (mot_x) FreeImage(mot_x);
	if (mot_y) FreeImage(mot_y);

	ImageRepetitivePadding(reference->y_chan, 16);
	ImageRepetitivePadding(reference->u_chan, 8);
	ImageRepetitivePadding(reference->v_chan, 8);

	Bitstream_NextStartCode();	  

	return;
}
												  /* CodeVop() */


/***********************************************************CommentBegin******
函数功能:
本函数将完成视频对象平面头部句法的写入,它将头部句法的所有信息写到数据流磁盘文件中。
函数输入:
Vop* vop:指向包含有头部信息的视频对象平面的指针。
函数返回值:
UInt num_bits:被写入的比特位的个数。
函数描述:
视频对象平面的头部信息(起始编码,视频对象平面的ID等等)首先被写入,写入的格式是整形的比特流数据结构,然后再输出到磁盘文件中。

 ***********************************************************CommentEnd********/

Uint BitstreamPutVopHeader(Vop *vop, Float time, VolConfig *vol_config)
{
	Image *buffer = NULL;
	Int bits;
	Int time_modulo;
	Float time_inc;
	Int   index;

	UInt  num_bits_header=0;

	/*将视频对象平面头信息中的所有句法写入在数据结构中*/
	BitstreamPutBits(buffer,VOP_START_CODE,VOP_START_CODE_LENGTH);
	BitstreamPutBits(buffer,GetVopPredictionType(vop),2);

	index = GetVolConfigModTimeBase(vol_config, 1);

	time_modulo = (int)time - index*1000;
	while(time_modulo >= 1000)
	{
		BitstreamPutBits(buffer,1,1);
		time_modulo = time_modulo - 1000;
		index++;
		printf("time modulo : 1\n");
	}
	BitstreamPutBits(buffer,0,1);

	/*保存这种模时间基*/
	PutVolConfigModTimeBase(index,vol_config);

	time_inc = (time - index*1000);

	bits = (int)ceil(log((double)GetVopTimeIncrementResolution(vop))/log(2.0));
	if (bits<1) bits=1;
	time_inc=time_inc*GetVopTimeIncrementResolution(vop)/1000.0f;

	/*标志比特位*/
	BitstreamPutBits(buffer,1,1);

	BitstreamPutBits(buffer,(Int)(time_inc+0.001),bits);

	/*标志比特位*/
	BitstreamPutBits(buffer,1,1);

	if (GetVopWidth(vop)==0)
	{
		printf("Empty VOP at %.2f\n",time);		  
		BitstreamPutBits(buffer,0L,1L);
		num_bits_header += Bitstream_NextStartCode();
		return(num_bits_header);
	}
	else
		BitstreamPutBits(buffer,1L,1L);

	if( GetVopPredictionType(vop) == P_VOP )
		BitstreamPutBits(buffer,GetVopRoundingType(vop),1);

	BitstreamPutBits(buffer,GetVopIntraDCVlcThr(vop),3);

	if (GetVopPredictionType(vop) == I_VOP)	  /* I_VOP */
		BitstreamPutBits(buffer,GetVopIntraQuantizer(vop),GetVopQuantPrecision(vop));
	else   /* P_VOP */
		BitstreamPutBits(buffer,GetVopQuantizer(vop),GetVopQuantPrecision(vop));

	if (GetVopPredictionType(vop)!=I_VOP)
	{
		BitstreamPutBits(buffer,GetVopFCodeFor(vop),3);
	}

	return(num_bits_header);
}


// 完成图像的重复填充,在填充过程中,保证在边界设置上Y、U、V分别是16、4、4模式。
Void ImageRepetitivePadding(Image *image, Int edge)
{
	SInt *p, left, right;
	Int width, height, x, y;

	p = image->f;
	width = image->x;
	height = image->y;

	/* Horizontal Padding */
	for( y=edge; y<height-edge; y++)
    {
		left = p[y*width+edge];
		right = p[y*width+width-edge-1];
		for(x=0; x<edge; x++)
		{
			p[y*width+x] = left;
			p[y*width+width-edge+x] = right;
		}
    }

	/* Vertical Padding */
    for(y=0; y<edge; y++)
        for(x=0; x<width; x++)
            p[y*width+x] = p[edge*width+x];
		
	for(y=height-edge; y<height; y++)
		for(x=0; x<width; x++)
			p[y*width+x] = p[(height-1-edge)*width+x];
	
	return;
}


/***********************************************************CommentBegin******
 函数功能:
本函数用于计算视频对象平面的误差容忍值。
函数输入:
Vop* error_vop:存在残留误差的视频对象平面。
函数描述:
本函数仅仅在编码模式为I-VOP时才进行调用。

 ***********************************************************CommentEnd********/

Double compute_MAD(Vop  *error_vop)
{
	SInt  *curr_in,
		*curr_end;
	Float *curr_fin,
		*curr_fend;
	UInt   sxy_in;
	Double mad=0.0, dc = 0.0;
	Int    cnt=0;

	/*计算容忍值*/
	switch (GetImageType(error_vop->y_chan))
	{
		case SHORT_TYPE:
			/*计算AC频段的容忍值*/
			/* 首先要计算平均值*/
			curr_in = (SInt*)GetImageData(error_vop->y_chan);
			sxy_in = GetImageSize(error_vop->y_chan);
			curr_end = curr_in + sxy_in;
			cnt = 0;
			while (curr_in != curr_end)
			{
				dc += *curr_in; //abs(*curr_in);
				cnt++;
				curr_in++;
			}
			dc /= cnt;

			curr_in = (SInt*)GetImageData(error_vop->y_chan);
			sxy_in = GetImageSize(error_vop->y_chan);
			curr_end = curr_in + sxy_in;
			cnt = 0;
			while (curr_in != curr_end)
			{
				mad += fabs(*curr_in - dc);
				cnt++;
				curr_in++;
			}
			mad /= cnt;
			break;
		case FLOAT_TYPE:
			curr_fin = (Float*)GetImageData(error_vop->y_chan);
			sxy_in = GetImageSize(error_vop->y_chan);
			curr_fend = curr_fin + sxy_in;
			cnt = 0;
			while (curr_fin != curr_fend)
			{
				mad += fabs(*curr_fin);
				cnt++;
				curr_fin++;
			}
			mad /= cnt;
			break;
		default: break;
	}

#ifdef _RC_
	fprintf(ftrace, "The MAD of the VOP to be coded is %f.\n", mad);
#endif

	return mad;
}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -