diff options
author | Bent Bisballe Nyeng <deva@aasimon.org> | 2014-09-19 17:44:44 +0200 |
---|---|---|
committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2014-09-19 17:44:44 +0200 |
commit | 8ea0da109c1e8134b123f618b5e7df5274183e87 (patch) | |
tree | 69e4c3835a4ff7e23ac2abb12ff6b37d76637503 | |
parent | c44df0a4d48a217a7ecbdc5dbf792c10a11cd913 (diff) |
YUYV -> JPEG conversion (untested).
-rw-r--r-- | src/v4l.cc | 95 |
1 files changed, 92 insertions, 3 deletions
@@ -44,6 +44,13 @@ #include <linux/videodev2.h> +extern "C" { +#include <jpeglib.h> +} + +#define JPEG_HEADER_PAD 500 + +static bool isYUYV = false; static V4L *v4l = NULL; #define CLEAR(x) memset(&(x), 0, sizeof(x)) @@ -85,9 +92,86 @@ static int xioctl(int fh, int request, void *arg) return r; } +/* + * In typical computer APIs, "YUV" actually means YCbCr, and "YUYV" means + * "YCbCr 4:2:2" stored as Y0, Cb01, Y1, Cr01, Y2 ... + */ +static void toJpeg(int quality, unsigned char *yuyv, + int image_width, int image_height, + char **out, size_t *size) +{ + JSAMPLE *image_buffer = (JSAMPLE*)yuyv; + + long unsigned int buffersize = + (image_width * image_height * 3) + JPEG_HEADER_PAD; + unsigned char *jpeg_output_buffer = (unsigned char *)malloc(buffersize); + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + + JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s] + int row_stride; // physical row width in image buffer + + // Allocate and initialize JPEG compression object + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + + // Specify data destination (see jpeg_mem_dest) + jpeg_mem_dest(&cinfo, &jpeg_output_buffer, &buffersize); + + // Set compression parameters + cinfo.image_width = image_width; // image width and height, in pixels + cinfo.image_height = image_height; + cinfo.input_components = 3; // # of color components per pixel + cinfo.in_color_space = JCS_RGB; // colorspace of input image + + jpeg_set_defaults(&cinfo); + + jpeg_set_quality(&cinfo, quality, TRUE); // limit to baseline-JPEG values + + // Start compressor + jpeg_start_compress(&cinfo, TRUE); + + // While (scan lines remain to be written) + row_stride = image_width * 3; // JSAMPLEs per row in image_buffer + + unsigned char *yuv = new unsigned char[image_width * 3]; + while (cinfo.next_scanline < cinfo.image_height) { + for (int i = 0; i < cinfo.image_width; i += 2) { + yuv[i*3] = yuyv[i*2]; + yuv[i*3+1] = yuyv[i*2+1]; + yuv[i*3+2] = yuyv[i*2+3]; + yuv[i*3+3] = yuyv[i*2+2]; + yuv[i*3+4] = yuyv[i*2+1]; + yuv[i*3+5] = yuyv[i*2+3]; + } + row_pointer[0] = yuv; + yuyv += image_width * 2; + jpeg_write_scanlines(&cinfo, row_pointer, 1); + + // row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + // (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + delete[] yuv; + + // Finish compression + jpeg_finish_compress(&cinfo); + + // Release JPEG compression object + jpeg_destroy_compress(&cinfo); + + *size = buffersize; + *out = (char*)jpeg_output_buffer; +} + static void process_image(const void *p, int size) { - if(v4l) v4l->processImage(p, size); + const void *img = p; + int img_size = size; + + if(isYUYV) { + toJpeg(70, (unsigned char*)p, 640, 480, (char**)&img, (size_t*)&img_size); + } + if(v4l) v4l->processImage(img, img_size); /* if (out_buf) fwrite(p, size, 1, stdout); @@ -528,10 +612,15 @@ static void init_device(void) format[4] = '\0'; printf("format: %s\n", format); if(strcmp(format, "JPEG")) { - printf("Webcam does not support JPEG...!\n"); - exit(1); + if(strcmp(format, "YUYV")) { + printf("Webcam neither supports JPEG nor YUYV...!\n"); + exit(1); + } else { + isYUYV = true; // Activate libJPEG encoding on each frame. + } } + /* Note VIDIOC_S_FMT may change width and height. */ } else { /* Preserve original settings as set by v4l2-ctl for example */ |