C++处理YUV格式视频【帧平均法】

1.原理图

这里是引用
2.处理函数,

class YuvOperationtwo {
    
    

public:

	
	void averageFrame(int totalPix,
		unsigned char* before_data, unsigned char* write_data, unsigned char* after_data);

};
void YuvOperationtwo::averageFrame(int totalPix,
	unsigned char* before_frame, unsigned char* write_frame, unsigned char* after_frame) {
    
    

	//前一帧,写入帧,后一帧的活动指针
	unsigned char* activity_before_frame = before_frame;
	unsigned char* w_write_frame = write_frame;
	unsigned char* activity_after_frame = after_frame;

	for (int j = 1; j <= totalPix; j++) {
    
    

		//除2是因为d1与d2相同
		*w_write_frame = *activity_before_frame / 2 + *activity_after_frame / 2;
		w_write_frame++;
		activity_before_frame++;
		activity_after_frame++;
	}
}

调用

const char* inPath = "D:\\YUM\\experiment three\\RaceHorses_416x240_30.yuv";
	const char* outOddPath = "D:\\YUM\\experiment three\\RaceHorses_416x240_30_odd.yuv";
	FILE* fin = fopen(inPath, "rb+");
	if (!fin) {
    
    
		cout << "Open file failed!" << endl;
		return -1;
	}

	FILE* fout = fopen(outOddPath, "a");
	if (!fout) {
    
    
		cout << "Open file failed!" << endl;
		return -1;
	}

	int width = 416;
	int height = 240; 
	int totalPix = int(width * height * 1.5);//每帧像素个数为416×240,420视频序列yuv每个像素占用1.5byte的像素空间。
	int nFrame, size;
	fseek(fin, 0, SEEK_END);   //将文件指针移到文件末尾,偏移0个字节;fseek(fp,50L,0);或fseek(fp,50L,SEEK_SET);解释:其作用是将位置指针移到离文件头50个字节处
	size = ftell(fin);     //得到文件尾相对于文件首的位移,即文件的总字节数
	rewind(fin);       //重置文件指针指向文件头部
	nFrame = size / totalPix; //得到视频文件的总帧数
	cout << "视频总帧数:" << nFrame << endl;
	
	//这里只能用unsigned char 不能用char。
	unsigned char* before_frame = new unsigned char[totalPix]();		//前一帧
	unsigned char* write_frame = new unsigned char[totalPix]();		//预测帧
	unsigned char* after_frame = new unsigned char[totalPix]();		//后一帧
	//nFrame可理解为生成的帧数,10--》生成10帧
	for (int frame = 0; frame < nFrame; frame++) {
    
    

		//读取1-2-3。。。帧
		fread(before_frame, 1, totalPix, fin);		
		//读取2-3-4。。。帧
		fread(after_frame, 1, totalPix, fin);
		//第二次读取时候文件指针移动到第2帧处,需要向后移动一帧大小的位数
		fseek(fin, -totalPix, SEEK_CUR);	
		YuvOperationtwo y;
		y.averageFrame(totalPix, before_frame, write_frame, after_frame);

		fwrite(write_frame, 1, totalPix, fout);
	}
	fclose(fin);
	fclose(fout);
	system("pause");
	return 0;

踩坑1

unsigned char 和 char的区别:

虽然都是占用1个字节,8位,且都能表示256个数字,但是char表示的范围为-128~127,而unsigned char表示的范围为0-255。在读取yuv二进制文件时候出现单个位数大于127的情况,就会导致出问题。如
unsigned char uc=255; char c=255; printf("%d %d",uc,c); 结果为: 255 -1
因为char类型表示有符号数,而二进制中最高位表示正负,255二进制表示为11111111在计算机内进行存储,为补码形式,转化为原码即为-1。

踩坑2

在进行测试不使用函数的情况下,活动指针必须要放在循环体里边,不能放在循环体外部。
这里是引用

踩坑3

在仅处理1,2帧得到1和2之间的插入帧时候也要使用中间指针,不能使用原定义的数组,这里不是多清楚原因,从java到c++底子太弱了。
在这里插入图片描述

分开处理YUV的写法

1.函数

class YuvOperationtwo {
    
    
public:
	void averageFrameYuv(int width, int hegith,
		unsigned char* before_y_read_data, unsigned char* before_u_read_data, unsigned char* before_v_read_data
		, unsigned char* y_write_data, unsigned char* u_write_data, unsigned char* v_write_data
		, unsigned char* after_y_read_data, unsigned char* after_u_read_data, unsigned char* after_v_read_data);
};

void YuvOperationtwo::averageFrameYuv(int width,int hegith,
	unsigned char* before_y_read_data, unsigned char* before_u_read_data, unsigned char* before_v_read_data
	, unsigned  char* y_write_data, unsigned  char*u_write_data, unsigned  char* v_write_data
	, unsigned char* after_y_read_data, unsigned char* after_u_read_data, unsigned  char* after_v_read_data) {
    
    

	//前一帧的yuv--游标指针
	unsigned char* read_before_y = before_y_read_data;
	unsigned char* read_before_u = before_u_read_data;
	unsigned char* read_before_v = before_v_read_data;

	//后一帧的yuv--游标指针
	unsigned char* read_after_y = after_y_read_data;
	unsigned char* read_after_u = after_u_read_data;
	unsigned char* read_after_v = after_v_read_data;

	//要写入的yuv
	unsigned char* write_img_y = y_write_data;
	unsigned char* write_img_u = u_write_data;
	unsigned char* write_img_v = v_write_data;


	int yWidth = width;
	int yHeight = hegith;

	int uvWidth = width / 2;
	int uvHeight = hegith / 2;


	int i = 0, j = 0;
	//对Y分量进行前后平均预测
	for (i = 0; i < yHeight; i++) {
    
    
		for (j = 0; j < yWidth; j++) {
    
    
			*write_img_y = *read_before_y / 2 + *read_after_y / 2;
			write_img_y++;
			read_before_y++;
			read_after_y++;
		}
	}
	//对UV分量进行前后预测
	for (i = 0; i < uvHeight; i++) {
    
    
		for (j = 0; j < uvWidth; j++) {
    
    
			*write_img_u = *read_before_u / 2 + *read_after_u / 2;
			write_img_u++;
			read_before_u++;
			read_after_u++;

			*write_img_v = *read_before_v / 2 + *read_after_v / 2;
			write_img_v++;
			read_before_v++;
			read_after_v++;
		}
	}

主函数

const char* inPath = "D:\\YUM\\experiment three\\RaceHorses_416x240_30.yuv";
	const char* outOddPath = "D:\\YUM\\experiment three\\RaceHorses_416x240_30_odd.yuv";
	FILE* fin = fopen(inPath, "rb+");
	if (!fin) {
    
    
		cout << "Open file failed!" << endl;
		return -1;
	}
	FILE* fout = fopen(outOddPath, "a");
	if (!fout) {
    
    
		cout << "Open file failed!" << endl;
		return -1;
	}

	int width = 416;
	int height = 240;
	int totalSize = width * height;
	int nFrame = 0, fileTotalSize = 0;
	int totalPix = int(width * height * 1.5);//每帧像素个数为416×240,420视频序列yuv每个像素占用1.5byte的像素空间。

	unsigned char* before_frame_y = new unsigned  char[totalSize]();
	unsigned char* before_frame_u = new unsigned char[totalSize / 4]();
	unsigned char* before_frame_v = new unsigned char[totalSize / 4]();

	unsigned char* write_frame_y = new unsigned char[totalSize]();
	unsigned char* write_frame_u = new unsigned char[totalSize / 4]();
	unsigned char* write_frame_v = new unsigned char[totalSize / 4]();

	unsigned char* after_frame_y = new unsigned char[totalSize]();
	unsigned char* after_frame_u = new unsigned char[totalSize / 4]();
	unsigned char* after_frame_v = new unsigned char[totalSize / 4]();
	for (int frame = 0; frame < 10; frame++) {
    
    
		fread(before_frame_y, totalSize, 1, fin);
		fread(before_frame_u, totalSize/4, 1, fin);
		fread(before_frame_v, totalSize/4, 1, fin);

		fread(after_frame_y, totalSize, 1, fin);
		fread(after_frame_u, totalSize / 4, 1, fin);
		fread(after_frame_v, totalSize / 4, 1, fin);

		fseek(fin, -totalPix, SEEK_CUR);
		
		YuvOperationtwo y;
		y.averageFrameYuv(width, height, before_frame_y, before_frame_u, before_frame_v,
			write_frame_y, write_frame_u, write_frame_v, after_frame_y, after_frame_u, after_frame_v);
		
		fwrite(write_frame_y, totalSize, 1, fout);
		fwrite(write_frame_u, totalSize / 4, 1, fout);
		fwrite(write_frame_v, totalSize / 4, 1, fout);
	
	}
	fclose(fin);
	fclose(fout);
	system("pause");
	return 1;

猜你喜欢

转载自blog.csdn.net/weixin_43917045/article/details/127150764
今日推荐