#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ccvt.h"
#include "v4l/v4l.h"
#include <jpeglib.h>
#include <jerror.h>
#include <jconfig.h>
#define DEFAULT_PALETTE VIDEO_PALETTE_YUV420P
//#define DEFAULT_PALETTE VIDEO_PALETTE_RGB24
//if need to debug, please open it
//#define DEBUG 0
#define PUSH_RGB24 1
#define PUSH_BGR24 2
#define PUSH_RGB32 3
#define PUSH_BGR32 4
#define IMAGE_WIDTH 320
#define IMAGE_HEIGHT 240
v4l_device vd;
int device_init(char *dev,int norm)
{
int i;
if(dev == NULL)
{
dev = "/dev/v4l/video0"; //set to default device
}
if(v4l_open(dev,&vd)) return -1;
if(v4l_get_channels(&vd)) return -1;
if(v4l_set_norm(&vd,norm)) return -1;
if(v4l_mmap_init(&vd)) return -1;
#ifdef DEBUG
printf("%s: initialization Ok... %s\n %d channels \n %d audios \n"
,dev,vd.capability.name,vd.capability.channels
,vd.capability.audios);
for(i=0;i<vd.capability.channels;i++)
{
printf("Channel %d: %s \n",i,vd.channel[i].name);
}
printf("v4l:mmap's address = %p\n",vd.map);
printf("v4l:mmap's buffer size = 0x%x\n",vd.mbuf.size);
printf("v4l:mmap's frames = %d(%d max)\n",vd.mbuf.frames,VIDEO_MAX_FRAME);
for(i=0; i< vd.mbuf.frames;i++)
{
printf("v4l: frames %d's offset = 0x%x\n",i,vd.mbuf.offsets[i]);
}
#endif
//start initialize grab
if(v4l_get_picture(&vd)) return -1;
if(v4l_set_palette(&vd,DEFAULT_PALETTE)) return -1;
#ifdef DEBUG
printf("test open 3\n");
#endif
if(v4l_grab_init(&vd,IMAGE_WIDTH,IMAGE_HEIGHT)) return -1;
if(v4l_grab_sync(&vd)) return -1;
#ifdef DEBUG
printf("test open 4\n");
#endif
return 0;
}
int device_grab_frame()
{
vd.frame_current = 0;
if(v4l_grab_frame(&vd,0) < 0) return -1;
return 0;
}
int device_next_frame()
{
vd.frame_current ^= 1;
if(v4l_grab_frame(&vd,vd.frame_current) < 0) return -1;
return 0;
}
/* This is a simplistic approach. */
static void ccvt_420p(int width, int height, const unsigned char *src, unsigned char *dst, int push)
{
int line, col, linewidth;
int y, u, v, yy, vr, ug, vg, ub;
int r, g, b;
const unsigned char *py, *pu, *pv;
linewidth = width >> 1;
py = src;
pu = py + (width * height);
pv = pu + (width * height) / 4;
y = *py++;
yy = y << 8;
u = *pu - 128;
ug = 88 * u;
ub = 454 * u;
v = *pv - 128;
vg = 183 * v;
vr = 359 * v;
for (line = 0; line < height; line++) {
for (col = 0; col < width; col++) {
r = (yy + vr) >> 8;
g = (yy - ug - vg) >> 8;
b = (yy + ub ) >> 8;
if (r < 0) r = 0;
if (r > 255) r = 255;
if (g < 0) g = 0;
if (g > 255) g = 255;
if (b < 0) b = 0;
if (b > 255) b = 255;
switch(push) {
case PUSH_RGB24:
*dst++ = r;
*dst++ = g;
*dst++ = b;
break;
case PUSH_BGR24:
*dst++ = b;
*dst++ = g;
*dst++ = r;
break;
case PUSH_RGB32:
*dst++ = r;
*dst++ = g;
*dst++ = b;
*dst++ = 0;
break;
case PUSH_BGR32:
*dst++ = b;
*dst++ = g;
*dst++ = r;
*dst++ = 0;
break;
}
y = *py++;
yy = y << 8;
if (col & 1) {
pu++;
pv++;
u = *pu - 128;
ug = 88 * u;
ub = 454 * u;
v = *pv - 128;
vg = 183 * v;
vr = 359 * v;
}
} /* ..for col */
if ((line & 1) == 0) { // even line: rewind
pu -= linewidth;
pv -= linewidth;
}
} /* ..for line */
}
void ccvt_420p_rgb24(int width, int height, const void *src, void *dst)
{
ccvt_420p(width, height, (const unsigned char *)src, (unsigned char *)dst, PUSH_RGB24);
}
void ccvt_420p_bgr24(int width, int height, const void *src, void *dst)
{
ccvt_420p(width, height, (const unsigned char *)src, (unsigned char *)dst, PUSH_BGR24);
}
void ccvt_420p_rgb32(int width, int height, const void *src, void *dst)
{
ccvt_420p(width, height, (const unsigned char *)src, (unsigned char *)dst, PUSH_RGB32);
}
void ccvt_420p_bgr32(int width, int height, const void *src, void *dst)
{
ccvt_420p(width, height, (const unsigned char *)src, (unsigned char *)dst, PUSH_BGR32);
}
int write_jpeg(char *filename, unsigned char *img,int quality,int gray)
{
FILE *fp;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
unsigned int i;
unsigned char *line;
int line_length;
if(NULL == (fp = fopen(filename,"w")))
{
fprintf(stderr,"grab: can't open %s\n",filename);
return -1;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, fp);
cinfo.image_width = IMAGE_WIDTH;
cinfo.image_height = IMAGE_HEIGHT;
cinfo.input_components = gray ? 1 : 3 ;
cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB;
#ifdef DEBUG
printf("test jpeg stage 1 ok\n");
#endif
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo,quality,TRUE);
jpeg_start_compress(&cinfo,TRUE);
#ifdef DEBUG
printf("test jpeg stage 2 ok\n");
#endif
line_length = gray ? IMAGE_WIDTH : IMAGE_WIDTH*3;
for(i=0,line=img;i<IMAGE_HEIGHT;i++,line+=line_length)
jpeg_write_scanlines(&cinfo,&line,1);
jpeg_finish_compress(&(cinfo));
jpeg_destroy_compress(&(cinfo));
fclose(fp);
#ifdef DEBUG
printf("test jpeg stage 3 ok\n");
#endif
return 0;
}
int main()
{
unsigned char *img;
unsigned char *img_out = malloc(IMAGE_WIDTH*IMAGE_HEIGHT*3);
FILE *fp;
memset(img_out,0,sizeof(img_out));
if(device_init("/dev/v4l/video0",3) == -1)
{
perror("device_init:failed...\n");
exit(1);
}
else
{
#ifdef DEBUG
printf("OK!\n");
#endif
//device_next_frame();
//device_grab_frame();
img = device_get_address(&vd);
#ifdef DEBUG
printf("img address is: %p \n",img);
printf("img_out address is: %p \n",img_out);
#endif
ccvt_420p_rgb24(IMAGE_WIDTH,IMAGE_HEIGHT,img,img_out);
#ifdef DEBUG
printf("ccvt_420p_rgb24_ok\n");
fp = fopen("test.ppm","w");
fprintf(fp,"P6\n%d %d\n255\n",IMAGE_WIDTH,IMAGE_HEIGHT);
fwrite(img_out,IMAGE_WIDTH*3,IMAGE_HEIGHT,fp);
fclose(fp);
#endif
write_jpeg("test.jpeg", img_out , 75, 0);
#ifdef DEBUG
printf("write_jpeg_ok\n");
#endif
}
exit(0);
}