<二> 摄像头画面显示

    摄像头画面显示的程序比较简单,友善之臂的光盘里面已经提供了相关的代码,这里对其进行简单的封装,以便后续工程的使用。

    首先从main函数看起,代码如下。

/*
 * main.cpp
 *
 *  Created on: 2015年12月4日
 *      Author: Westlor
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "camera.h"
#include "Fb.h"

#define CAM_DEV		"/dev/video0"
#define FB_DEV		"/dev/fb0"
Camera *camera;
Fb *fb;

void sign_func(int sign_num)
{
    switch(sign_num)
    {
        case SIGINT:
            printf("I have get SIGINT<Ctrl+c>, I'm going now..\n");
            camera->CloseDevice();
			fb->CloseDevice();
            exit(0);
            break;
    }
}

int main(void) {

    int width=640;
    int height=480;
    unsigned char* image;

    camera=new Camera(CAM_DEV, width, height);
    if(!camera->OpenDevice()){
        printf("Cam Open error\n");
    	return -1;
    }
    fb = new Fb(FB_DEV,  80, 0, width, height);
    if(!fb->OpenDevice()){
    	printf("Fb Open error\n");
    	return -1;
    }

    fb->Trans(&image);
    printf("Waiting for signal SIGINT..\n");
    signal(SIGINT, sign_func);

    while(1){

    	if(!camera->GetBuffer(image)){
            break;
        }
        fb->Draw();
    }

    return 0;
}


    这里定义了两个类,Camera类的构造函数里定义了摄像头输入图像的宽和高,Fb类的构造函数里定义了液晶屏上显示图像的位置(x,y)以及大小。首先定义一个缓冲区,用来存储要显示的数据。在主循环中,不断读取摄像头采集度图像数据,并将其进行格式转换后放到缓冲区中,然后将缓冲区的数据拷贝到framebuffer中即可。

    接下来看摄像头初始化部分,对摄像头配置代码如下。

bool Camera::init_device(void) {

    v4l2_input input;
    memset(&input, 0, sizeof(struct v4l2_input));
    input.index = 0;
    if (ioctl(fd, VIDIOC_ENUMINPUT, &input) != 0) {

		fprintf(stderr, "No matching index found\n");
		return false;
	}
	if (!input.name) {

		fprintf(stderr, "No matching index found\n");
		return false;
	}
	if (ioctl(fd, VIDIOC_S_INPUT, &input) < 0) {

		fprintf(stderr, "VIDIOC_S_INPUT failed\n");
		return false;
	}

    struct v4l2_format fmt;
    CLEAR (fmt);
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = width;
    fmt.fmt.pix.height = height;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
    fmt.fmt.pix.field = V4L2_FIELD_NONE;

    if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
        return false;
    if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt))
        return false;

    //原始摄像头数据每帧的大小
    cap_image_size = fmt.fmt.pix.sizeimage;
    init_mmap();

    return true;
}

    这里配置摄像头图像格式为NV12,因为后面h264编码是需要摄像头图像格式为NV12。NV12为YUV420格式,每个像素占12位,平均是Y分量占8位,UV分量各占两位,存储时在线性模式下先存储Y分量,占前2/3,然后在剩余1/3空间里交叉存储UV分量。

    然后看液晶屏初始化的代码,对屏幕显示配置的代码如下。

bool Fb::init_device(void) {

	struct fb_fix_screeninfo Fix;
	struct fb_var_screeninfo Var;
	if (ioctl(fd, FBIOGET_FSCREENINFO, bitand Fix) < 0 or ioctl(fd, FBIOGET_VSCREENINFO, bitand Var) < 0) {
		printf("cannot get frame buffer information\n");
	}

	BPP = Var.bits_per_pixel;
	if (BPP not_eq 32) {
		printf("support 32 BPP frame buffer only\n");
	}

	Width  = Var.xres;
	Height = Var.yres;
	LineLen = Fix.line_length;
	Size = LineLen * Height;

	Addr = (unsigned char *)mmap(NULL, Size, PROT_READ|PROT_WRITE,MAP_SHARED, fd, 0);
	if (Addr == (unsigned char *)MAP_FAILED) {

		printf("map frame buffer failed\n");
		return false;
	}

	show_buffer = (unsigned char*)malloc(show_width*show_height*BPP/8);
	if(show_buffer == NULL){

		printf("buffers malloc failed\n");
		return false;
	}

	Clear();		//清空屏幕
	return true;
}

    屏幕所显示的图像格式为rgb,每个像素为32位的,rgb分量各占8位,还有8位是透明度的分量。从摄像头取来的图像转换到屏幕上显示时需要做格式转换,即NV12->rgb。下面是图像格式转换代码。申请内存的时候需要注意存储空间的大小,NV12的对应为 H*W*12/8,rgb的对应为 H*W*32/8。

void Camera::DecodeYUV420SP(unsigned int* rgbBuf, unsigned char* yuv420sp, int width, int height) {
    int frameSize = width * height;

    int i = 0, y = 0;
    int uvp = 0, u = 0, v = 0;
    int y1192 = 0, r = 0, g = 0, b = 0;
    unsigned int xrgb8888;
    int xrgb8888Index = 0;

    for (int j = 0, yp = 0; j < height; j++) {
        uvp = frameSize + (j >> 1) * width;
        u = 0;
        v = 0;
        for (i = 0; i < width; i++, yp++) {
            y = (0xff & ((int) yuv420sp[yp])) - 16;
            if (y < 0) y = 0;
            if ((i & 1) == 0) {
                v = (0xff & yuv420sp[uvp++]) - 128;
                u = (0xff & yuv420sp[uvp++]) - 128;
            }

            y1192 = 1192 * y;
			r = (y1192 + 1634 * u);
			g = (y1192 - 833 * u - 400 * v);
			b = (y1192 + 2066 * v);

            if (r < 0) r = 0; else if (r > 262143) r = 262143;
            if (g < 0) g = 0; else if (g > 262143) g = 262143;
            if (b < 0) b = 0; else if (b > 262143) b = 262143;


            r = (unsigned char)(r >> 10);
            g = (unsigned char)(g >> 10);
            b = (unsigned char)(b >> 10);

            xrgb8888 = (unsigned int)((r << 16) | (g << 8) | b);
            rgbBuf[xrgb8888Index++] = xrgb8888;
        }
    }
}
    程序可以在 http://download.csdn.net/detail/westlor/9389478下载。





  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值