攝像頭畫面顯示

    攝像頭畫面顯示的程序比較簡單,友善之臂的光盤裏面已經提供了相關的代碼,這裏對其進行簡單的封裝,以便後續工程的使用。

    首先從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下載。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章