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;