]> rtime.felk.cvut.cz Git - eurobot/public.git/commitdiff
camera support added -- starting with JPEG decoding
authorMarek Peca <mp@duch.cz>
Fri, 17 Apr 2009 18:33:28 +0000 (20:33 +0200)
committerMarek Peca <mp@duch.cz>
Fri, 17 Apr 2009 18:33:28 +0000 (20:33 +0200)
requires IJG JPEG library (libjpeg).. to be OMKized later

src/camera/rozpuk/decjpeg.c [new file with mode: 0644]
src/camera/rozpuk/decjpeg.h [new file with mode: 0644]
src/camera/rozpuk/jpegdemo.c [new file with mode: 0644]

diff --git a/src/camera/rozpuk/decjpeg.c b/src/camera/rozpuk/decjpeg.c
new file mode 100644 (file)
index 0000000..6f86972
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * JPEG decoding using IJG libjpeg
+ * tested with library release 6b of 27-Mar-1998 (jpegsrc.v6b.tar.gz)
+ *
+ * based on djpeg.c & example.c, (c) 1991-1997, Thomas G. Lane,
+ *  part of the Independent JPEG Group's software.
+ *
+ * adapted by Marek Peca <mp@duch.cz> 2009/04
+ *   for the EUROBOT competition team
+ *   of the Dept. of Control Engineering  http://dce.fel.cvut.cz/
+ */
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <sys/types.h>
+#include <stdio.h>
+
+#include <jpeglib.h>
+
+#include "decjpeg.h"
+
+/** error manager **/
+
+struct error_mgr {
+  struct jpeg_error_mgr jerr;
+  jmp_buf setjmp_addr;
+};
+
+void error_exit(j_common_ptr cinfo) {
+  struct error_mgr *err = (struct error_mgr*)cinfo->err;
+  longjmp(err->setjmp_addr, 1);
+}
+
+/** compressed source manager **/
+
+struct source_mgr {
+  struct jpeg_source_mgr jsrc;
+  uint8_t *buffer;
+  size_t length;
+};
+
+void init_source(j_decompress_ptr cinfo) {
+  struct source_mgr *src = (struct source_mgr*)cinfo->src;
+
+  src->jsrc.next_input_byte = src->buffer;
+  src->jsrc.bytes_in_buffer = src->length;
+}
+
+boolean fill_input_buffer(j_decompress_ptr cinfo) {
+  return FALSE;
+}
+
+void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
+  struct source_mgr *src = (struct source_mgr*)cinfo->src;
+
+  src->jsrc.next_input_byte += (size_t)num_bytes;
+  src->jsrc.bytes_in_buffer -= (size_t)num_bytes;
+}
+
+void term_source(j_decompress_ptr cinfo) {
+  /*NOP*/
+}
+
+/** actual decoding routine **/
+
+/**
+ * Decode JPEG image to RGB image, from memory buffer to memory buffer
+ * @param jpeg JPEG encoded image data
+ * @param jpeg_size >= actual length of JPEG data
+ * @param rgb RGB (24 bit) output buffer
+ * @param max_rgb_size >= size of RGB buffer (stop filling and return without
+ *   an error, if full)
+ * @param w return width (NULL if not interested)
+ * @param h return height (NULL if not interested)
+ * @return -1 fatal error occured, 0 OK, >0 number of JPEG lib warnings
+ */
+int jpeg_decode(uint8_t *jpeg, size_t jpeg_size,
+               uint8_t *rgb, size_t max_rgb_size,
+               unsigned *w, unsigned *h)
+{
+  struct jpeg_decompress_struct cinfo;
+  struct error_mgr err;
+  struct source_mgr src;
+  uint8_t *ptr = rgb, *out_row[] = { ptr };
+  size_t row_size;
+
+  jpeg_create_decompress(&cinfo);
+
+#if 1
+  /* setup custom error handling (deactivate default exit()) */
+  cinfo.err = jpeg_std_error(&err.jerr);
+  err.jerr.error_exit = error_exit;
+  if (setjmp(err.setjmp_addr)) {
+    jpeg_destroy_decompress(&cinfo);
+    /* fatal error occured */
+    return -1;
+  }
+#else
+  struct jpeg_error_mgr jerr;
+  cinfo.err = jpeg_std_error(&jerr);
+#endif
+
+#if 1
+  /* initialize custom source -- whole JPEG memory buffer */
+  cinfo.src = (struct jpeg_source_mgr*)&src;
+  src.jsrc.init_source = init_source;
+  src.jsrc.fill_input_buffer = fill_input_buffer;
+  src.jsrc.skip_input_data = skip_input_data;
+  src.jsrc.resync_to_restart = jpeg_resync_to_restart; /* default */
+  src.jsrc.term_source = term_source;
+  src.buffer = jpeg;
+  src.length = jpeg_size;
+  /* should it be here, or in init_source only? */
+  src.jsrc.next_input_byte = src.buffer;
+  src.jsrc.bytes_in_buffer = src.length;
+#else
+  jpeg_stdio_src(&cinfo, stdin);
+#endif
+
+  jpeg_read_header(&cinfo, TRUE);
+
+  if (w)
+    *w = cinfo.image_width;
+  if (h)
+    *h = cinfo.image_height;
+
+  /* RGB should be selected.. */
+
+  jpeg_start_decompress(&cinfo);
+
+  row_size = 3*cinfo.output_width;
+  while ((cinfo.output_scanline < cinfo.output_height) &&
+        (ptr + row_size <= rgb + max_rgb_size)) {
+    out_row[0] = ptr;
+    jpeg_read_scanlines(&cinfo, out_row, 1);
+    ptr += row_size;
+  }
+
+  jpeg_finish_decompress(&cinfo);
+  jpeg_destroy_decompress(&cinfo);
+
+  /* 0 no problems, >0 some warnings */
+  return err.jerr.num_warnings;
+}
diff --git a/src/camera/rozpuk/decjpeg.h b/src/camera/rozpuk/decjpeg.h
new file mode 100644 (file)
index 0000000..877269b
--- /dev/null
@@ -0,0 +1,6 @@
+#include <inttypes.h>
+#include <sys/types.h>
+
+int jpeg_decode(uint8_t *jpeg, size_t jpeg_size,
+               uint8_t *rgb, size_t max_rgb_size,
+               unsigned *w, unsigned *h);
diff --git a/src/camera/rozpuk/jpegdemo.c b/src/camera/rozpuk/jpegdemo.c
new file mode 100644 (file)
index 0000000..6d4f105
--- /dev/null
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+#include "decjpeg.h"
+
+#define MAXLEN (640*480*3)
+
+uint8_t jpeg[MAXLEN], rgb[MAXLEN];
+
+int main() {
+  unsigned w, h;
+  int rc;
+
+  fread(jpeg, 1, MAXLEN, stdin);
+  rc = jpeg_decode(jpeg, MAXLEN, rgb, MAXLEN, &w, &h);
+  fprintf(stderr, "rc=%d, w=%d, h=%d\n", rc, w, h);
+  fwrite(rgb, 1, w*h*3, stdout);
+
+  return 0;
+}