summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2014-09-19 17:44:44 +0200
committerBent Bisballe Nyeng <deva@aasimon.org>2014-09-19 17:44:44 +0200
commit8ea0da109c1e8134b123f618b5e7df5274183e87 (patch)
tree69e4c3835a4ff7e23ac2abb12ff6b37d76637503
parentc44df0a4d48a217a7ecbdc5dbf792c10a11cd913 (diff)
YUYV -> JPEG conversion (untested).
-rw-r--r--src/v4l.cc95
1 files changed, 92 insertions, 3 deletions
diff --git a/src/v4l.cc b/src/v4l.cc
index 7d8ed3f..c83da06 100644
--- a/src/v4l.cc
+++ b/src/v4l.cc
@@ -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 */