把yuv422 转为rgb32 ,利用framebuffer 显示
经实验,可以显示任意尺寸大小的yuv图片
再利用此基础,就可以在文本终端中显示yuyv
格式的视频。
特别要注意:1:YUYV 是4字节存储两个像素,UV 这两个字节共用
2:YUYV422 二字节中的低字节代表Y,高为U 或者V
3:RGB32 :是4字节,低字节为B,第2为G,第3为R,第4为空
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h> //v4l2 头文件
#include <string.h>
#include <sys/mman.h>
#include <linux/fb.h>
#define pic_width 640 //1280*720 640*480 960*540
#define pic_heigth 480
#define pic_path "/home/wjs/Pictures/my.yuv"
#define WT 10 //如果图片是斜的,微调此值
static int color1=0;
static int color2=0;
static int sp[3000*2000]; //取摄像头最大尺寸
static struct fb_var_screeninfo var;
int main(void)
{
FILE *f=fopen(pic_path,"r+b");
if(f==NULL){
puts("file error");
exit(-1);
}
fseek(f,0,SEEK_END);
int len=ftell(f);
fseek(f,0,SEEK_SET);
int fd=fileno(f);
char *p1=mmap(NULL,len,PROT_READ,MAP_SHARED,fd,0);
char (*p)[4]=(char (*)[4])p1; // p[][0]=Y p[][1]=U p[][2]=Y p[][3]=V
//R = Y + 1.4075 *(V-128)
//G = Y – 0.3455 *(U –128) – 0.7169 *(V –128)
// B = Y + 1.779 *(U – 128)
int t=0;
int u=0;
while(1){
if(4*t>=len){
break;
}
int Y1=(unsigned char)p[t][0];
if((4*t+1)>=len){
break;
}
int U=(unsigned char)p[t][1];
if((4*t+2)>=len){
break;
}
int Y2=(unsigned char)p[t][2];
if((4*t+3)>=len){
break;
}
int V=(unsigned char)p[t][3];
//-------------------------------------------------
int B0=Y1+1.779*(U-128);
if(B0>255) B0=255;
if(B0<0) B0=0;
int G0=Y1-0.3455*(U-128)-0.7169*(V-128);
if(G0>255) G0=255;
if(G0<0) G0=0;
int R0=Y1+1.4075*(V-128);
if(R0>255) R0=255;
if(R0<0) R0=0;
int B1=Y2+1.779*(U-128);
if(B1>255) B1=255;
if(B1<0) B1=0;
int G1=Y2-0.3455*(U-128)-0.7169*(V-128);
if(G1>255) G1=255;
if(G1<0) G1=0;
int R1=Y2+1.4075*(V-128);
if(R1>255) R1=255;
if(R1<0) R1=0;
color1=(R0<<16)|(G0<<8)|B0;
color2=(R1<<16)|(G1<<8)|B1;
sp[u]=color1;
sp[u+1]=color2;
t++;
u=u+2;
}
munmap(p1,len);
puts("yuyv over");
//--------------------------------
int fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0)
{
puts("/dev/fb0 error");
return -1;
}
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
puts("ioctl error");
return -1;
}
// unsigned int pixel_width = var.bits_per_pixel / 8; //deepin=32
int screen_size = var.xres * var.yres * var.bits_per_pixel / 8; //刚好等于图片的长乘宽
unsigned char *fb_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if (fb_base == NULL)
{
puts("mmap error");
return -1;
}
memset(fb_base,0, screen_size); //设底色为黑色
int zz=0;
var.xres=var.xres+WT; //如果图片是斜的,微调WT的值
for(int a=0;a<var.yres;a++){
for(int b=0;b<var.xres;b++){
unsigned int (*p)[var.xres]=(unsigned int (*)[var.xres])fb_base; //此处不能用图片的尺寸,因为有不同尺寸大小
if(b<pic_width){ //如果图片宽度小于framebuffer 的宽度,小与部分填充0(黑色)
p[a][b]=sp[zz]; //sp[zz]
zz++;
}else{
p[a][b]=0; //填充黑色
}
}
}
munmap(fb_base, screen_size);
close(fd_fb);
puts("over");
return 0;
}