[Ekiga-list] green screen

Luc Saillard luc at saillard.org
Sun Mar 4 10:16:11 UTC 2007


On Sat, Mar 03, 2007 at 08:09:59PM +0100, Rainer Bachl wrote:
> I want to confirm the problem reported by Gene Imes.
> The webcam screen remains green in Ekiga also with my setup.
> I am using a Creative Live! Cam Optia with v4l2 and
> the Linux driver for USB video class (linux-uvc).
> 

After investigating the case, the camera send some none standard value (but
it's correct). I've made a patch to fix the problem in pwlib. I've also
upgrade the jpeg devoder to take account the RST marker (normaly webcam
doesn't sent this marker ... but to synchronize with upstream it's more
easy).

Damien, would you want a patch that fix only the bug ? The next patch is
against pwlib-cvs, but i'm sure that i can be applied on pwlib-stable branch.

# HG changeset patch
# User "Luc Saillard <luc at saillard.org>"
# Date 1173003291 -3600
# Node ID 0ebd2ccf6da3884077559c3c2521936040b81fa2
# Parent  a5ea3f0f1fbe3af983f350d8a57541c399df4478
Fix a bug when the component id is not 1, 2 and 3.

  Some webcam encode the component id starting from 0, and not 1.
  So now, we use the order of the component and not the value given
  by the jpeg information. Sanity check will report wrong component
  id order now.

Handle restart interval marker.

  This slow down a little the processing (one more test for each MCU decoding).
  Perhaps we need to put this in #if ... #endif

Rename jpeg_idct_float into tinyjpeg_idct_float to avoid clash with the
libjpeg.

Fix a bug when a DHT table is present and not in the last position.

diff -r a5ea3f0f1fbe -r 0ebd2ccf6da3 src/ptlib/common/jidctflt.cxx
--- a/src/ptlib/common/jidctflt.cxx	Sun Mar 04 10:48:34 2007 +0100
+++ b/src/ptlib/common/jidctflt.cxx	Sun Mar 04 11:14:51 2007 +0100
@@ -133,7 +133,7 @@ static inline unsigned char descale_and_
  */
 
 void
-jpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride)
+tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride)
 {
   FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
   FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
diff -r a5ea3f0f1fbe -r 0ebd2ccf6da3 src/ptlib/common/tinyjpeg-internal.h
--- a/src/ptlib/common/tinyjpeg-internal.h	Sun Mar 04 10:48:34 2007 +0100
+++ b/src/ptlib/common/tinyjpeg-internal.h	Sun Mar 04 11:14:51 2007 +0100
@@ -37,6 +37,8 @@
 
 #include <setjmp.h>
 
+#define SANITY_CHECK 1
+
 struct jdec_private;
 
 #define HUFFMAN_HASH_NBITS 9
@@ -44,7 +46,9 @@ struct jdec_private;
 #define HUFFMAN_HASH_MASK  (HUFFMAN_HASH_SIZE-1)
 
 #define HUFFMAN_TABLES	   4
-#define COMPONENTS	   4
+#define COMPONENTS	   3
+#define JPEG_MAX_WIDTH	   2048
+#define JPEG_MAX_HEIGHT	   2048
 
 struct huffman_table
 {
@@ -68,6 +72,9 @@ struct component
   struct huffman_table *DC_table;
   short int previous_DC;	/* Previous DC coefficient */
   short int DCT[64];		/* DCT coef */
+#if SANITY_CHECK
+  unsigned int cid;
+#endif
 };
 
 
@@ -93,6 +100,9 @@ struct jdec_private
   struct huffman_table HTDC[HUFFMAN_TABLES];	/* DC huffman tables   */
   struct huffman_table HTAC[HUFFMAN_TABLES];	/* AC huffman tables   */
   int default_huffman_table_initialized;
+  int restart_interval;
+  int restarts_to_go;				/* MCUs left in this restart interval */
+  int last_rst_marker_seen;			/* Rst marker is incremented each time */
 
   /* Temp space used after the IDCT to store each components */
   uint8_t Y[64*4], Cr[64], Cb[64];
@@ -103,8 +113,8 @@ struct jdec_private
 
 };
 
-#define IDCT jpeg_idct_float
-void jpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride);
+#define IDCT tinyjpeg_idct_float
+void tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride);
 
 #endif
 
diff -r a5ea3f0f1fbe -r 0ebd2ccf6da3 src/ptlib/common/tinyjpeg.cxx
--- a/src/ptlib/common/tinyjpeg.cxx	Sun Mar 04 10:48:34 2007 +0100
+++ b/src/ptlib/common/tinyjpeg.cxx	Sun Mar 04 11:14:51 2007 +0100
@@ -47,25 +47,20 @@ enum std_markers {
    DHT  = 0xC4, /* Huffman Table */
    SOI  = 0xD8, /* Start of Image */
    SOS  = 0xDA, /* Start of Scan */
+   RST  = 0xD0, /* Reset Marker d0 -> .. */
+   RST7 = 0xD7, /* Reset Marker .. -> d7 */
    EOI  = 0xD9, /* End of Image */
+   DRI  = 0xDD, /* Define Restart Interval */
    APP0 = 0xE0,
 };
 
-#define cY	1
-#define cCb	2
-#define cCr	3
+#define cY	0
+#define cCb	1
+#define cCr	2
 
 #define BLACK_Y 0
 #define BLACK_U 127
 #define BLACK_V 127
-
-#define SANITY_CHECK 1
-
-#ifndef DEBUG
-#define DEBUG 0
-#define DUMP_TABLE 0
-#define LOG2FILE 0
-#endif
 
 #if DEBUG
 #if LOG2FILE
@@ -288,8 +283,15 @@ static const unsigned char val_ac_chromi
    result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
 }  while(0);
 
+/* To speed up the decoding, we assume that the reservoir have enough bit 
+ * slow version:
+ * #define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \
+ *   fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
+ *   nbits_in_reservoir -= (nbits_wanted); \
+ *   reservoir &= ((1U<<nbits_in_reservoir)-1); \
+ * }  while(0);
+ */
 #define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \
-   fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
    nbits_in_reservoir -= (nbits_wanted); \
    reservoir &= ((1U<<nbits_in_reservoir)-1); \
 }  while(0);
@@ -297,6 +299,7 @@ static const unsigned char val_ac_chromi
 
 #define be16_to_cpu(x) (((x)[0]<<8)|(x)[1])
 
+static void resync(struct jdec_private *priv);
 
 /**
  * Get the next (valid) huffman code in the stream.
@@ -373,6 +376,7 @@ static void process_Huffman_data_unit(st
   } else {
      DCT[0] = c->previous_DC;
   }
+
 
   /* AC coefficient decoding */
   j = 1;
@@ -400,7 +404,6 @@ static void process_Huffman_data_unit(st
 
   for (j = 0; j < 64; j++)
     c->DCT[j] = DCT[zigzag[j]];
-
 }
 
 /*
@@ -586,7 +589,7 @@ static void YCrCB_to_YUV420P_2x1(struct 
 {
   unsigned char *p;
   const unsigned char *s, *y1;
-  int i,j;
+  unsigned int i;
 
   p = priv->plane[0];
   y1 = priv->Y;
@@ -601,20 +604,18 @@ static void YCrCB_to_YUV420P_2x1(struct 
   s = priv->Cb;
   for (i=0; i<8; i+=2)
    {
-     for (j=0; j<8; j+=1, s+=1)
-       *p++ = *s;
-     s += 8; /* Skip one line */
-     p += priv->width/2 - 8;
+     memcpy(p, s, 8);
+     s += 16; /* Skip one line */
+     p += priv->width/2;
    }
 
   p = priv->plane[2];
   s = priv->Cr;
   for (i=0; i<8; i+=2)
    {
-     for (j=0; j<8; j+=1, s+=1)
-       *p++ = *s;
-     s += 8; /* Skip one line */
-     p += priv->width/2 - 8;
+     memcpy(p, s, 8);
+     s += 16; /* Skip one line */
+     p += priv->width/2;
    }
 }
 
@@ -727,7 +728,7 @@ static void YCrCB_to_RGB24_1x1(struct jd
   offset_to_next_row = priv->width*3 - 8*3;
   for (i=0; i<8; i++) {
 
-    for (j=0;j<8;j++) {
+    for (j=0; j<8; j++) {
 
        int y, cb, cr;
        int add_r, add_g, add_b;
@@ -782,7 +783,7 @@ static void YCrCB_to_BGR24_1x1(struct jd
   offset_to_next_row = priv->width*3 - 8*3;
   for (i=0; i<8; i++) {
 
-    for (j=0;j<8;j++) {
+    for (j=0; j<8; j++) {
 
        int y, cb, cr;
        int add_r, add_g, add_b;
@@ -1102,7 +1103,7 @@ static void YCrCB_to_RGB24_2x2(struct jd
   offset_to_next_row = (priv->width*3*2) - 16*3;
   for (i=0; i<8; i++) {
 
-    for (j=0;j<8;j++) {
+    for (j=0; j<8; j++) {
 
        int y, cb, cr;
        int add_r, add_g, add_b;
@@ -1185,7 +1186,7 @@ static void YCrCB_to_BGR24_2x2(struct jd
   offset_to_next_row = (priv->width*3*2) - 16*3;
   for (i=0; i<8; i++) {
 
-    for (j=0;j<8;j++) {
+    for (j=0; j<8; j++) {
 
        int y, cb, cr;
        int add_r, add_g, add_b;
@@ -1257,7 +1258,7 @@ static void YCrCB_to_Grey_1x1(struct jde
 
   p = priv->plane[0];
   y = priv->Y;
-  offset_to_next_row = priv->width-8;
+  offset_to_next_row = priv->width;
 
   for (i=0; i<8; i++) {
      memcpy(p, y, 8);
@@ -1586,14 +1587,15 @@ static void build_quantization_table(flo
 
 static int parse_DQT(struct jdec_private *priv, const unsigned char *stream)
 {
-  int length, qi;
+  int qi;
   float *table;
+  const unsigned char *dqt_block_end;
 
   trace("> DQT marker\n");
-  length = be16_to_cpu(stream) - 2;
+  dqt_block_end = stream + be16_to_cpu(stream);
   stream += 2;	/* Skip length */
 
-  while (length>0)
+  while (stream < dqt_block_end)
    {
      qi = *stream++;
 #if SANITY_CHECK
@@ -1605,8 +1607,8 @@ static int parse_DQT(struct jdec_private
      table = priv->Q_tables[qi];
      build_quantization_table(table, stream);
      stream += 64;
-     length -= 65;
-   }
+   }
+  trace("< DQT marker\n");
   return 0;
 }
 
@@ -1616,6 +1618,7 @@ static int parse_SOF(struct jdec_private
   int Q_table;
   struct component *c;
 
+  trace("> SOF marker\n");
   print_SOF(stream);
 
   height = be16_to_cpu(stream+3);
@@ -1624,7 +1627,7 @@ static int parse_SOF(struct jdec_private
 #if SANITY_CHECK
   if (stream[2] != 8)
     error("Precision other than 8 is not supported\n");
-  if (width>2048 || height>2048)
+  if (width>JPEG_MAX_WIDTH || height>JPEG_MAX_HEIGHT)
     error("Width and Height (%dx%d) seems suspicious\n", width, height);
   if (nr_components != 3)
     error("We only support YUV images\n");
@@ -1638,7 +1641,10 @@ static int parse_SOF(struct jdec_private
      cid = *stream++;
      sampling_factor = *stream++;
      Q_table = *stream++;
-     c = &priv->component_infos[cid];
+     c = &priv->component_infos[i];
+#if SANITY_CHECK
+     c->cid = cid;
+#endif
      c->Vfactor = sampling_factor&0xf;
      c->Hfactor = sampling_factor>>4;
      c->Q_table = priv->Q_tables[Q_table];
@@ -1649,6 +1655,8 @@ static int parse_SOF(struct jdec_private
   priv->width = width;
   priv->height = height;
 
+  trace("< SOF marker\n");
+
   return 0;
 }
 
@@ -1661,7 +1669,7 @@ static int parse_SOS(struct jdec_private
 
 #if SANITY_CHECK
   if (nr_components != 3)
-    error("We only support YUV image\n");
+    error("We only support YCbCr image\n");
 #endif
 
   stream += 3;
@@ -1673,12 +1681,16 @@ static int parse_SOS(struct jdec_private
 	error("We do not support more than 2 AC Huffman table\n");
      if ((table>>4)>=4)
 	error("We do not support more than 2 DC Huffman table\n");
+     if (cid != priv->component_infos[i].cid)
+        error("SOS cid order (%d:%d) isn't compatible with the SOF marker (%d:%d)\n",
+	      i, cid, i, priv->component_infos[i].cid);
      trace("ComponentId:%d  tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4);
 #endif
-     priv->component_infos[cid].AC_table = &priv->HTAC[table&0xf];
-     priv->component_infos[cid].DC_table = &priv->HTDC[table>>4];
+     priv->component_infos[i].AC_table = &priv->HTAC[table&0xf];
+     priv->component_infos[i].DC_table = &priv->HTDC[table>>4];
   }
   priv->stream = stream+3;
+  trace("< SOS marker\n");
   return 0;
 }
 
@@ -1726,6 +1738,32 @@ static int parse_DHT(struct jdec_private
   return 0;
 }
 
+static int parse_DRI(struct jdec_private *priv, const unsigned char *stream)
+{
+  unsigned int length;
+
+  trace("> DRI marker\n");
+
+  length = be16_to_cpu(stream);
+
+#if SANITY_CHECK
+  if (length != 4)
+    error("Length of DRI marker need to be 4\n");
+#endif
+
+  priv->restart_interval = be16_to_cpu(stream+2);
+
+#if DEBUG
+  trace("Restart interval = %d\n", priv->restart_interval);
+#endif
+
+  trace("< DRI marker\n");
+
+  return 0;
+}
+
+
+
 static void resync(struct jdec_private *priv)
 {
   int i;
@@ -1736,9 +1774,45 @@ static void resync(struct jdec_private *
 
   priv->reservoir = 0;
   priv->nbits_in_reservoir = 0;
-
-}
-
+  if (priv->restart_interval > 0)
+    priv->restarts_to_go = priv->restart_interval;
+  else
+    priv->restarts_to_go = -1;
+}
+
+static int find_next_rst_marker(struct jdec_private *priv)
+{
+  int rst_marker_found = 0;
+  int marker;
+  const unsigned char *stream = priv->stream;
+
+  /* Parse marker */
+  while (!rst_marker_found)
+   {
+     while (*stream++ != 0xff)
+      {
+	if (stream >= priv->stream_end)
+	  error("EOF while search for a RST marker.");
+      }
+     /* Skip any padding ff byte (this is normal) */
+     while (*stream == 0xff)
+       stream++;
+
+     marker = *stream++;
+     if ((RST+priv->last_rst_marker_seen) == marker)
+       rst_marker_found = 1;
+     else if (marker >= RST && marker <= RST7)
+       error("Wrong Reset marker found, abording");
+     else if (marker == EOI)
+       return 0;
+   }
+
+  priv->stream = stream;
+  priv->last_rst_marker_seen++;
+  priv->last_rst_marker_seen &= 7;
+
+  return 0;
+}
 
 static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream)
 {
@@ -1780,6 +1854,10 @@ static int parse_JFIF(struct jdec_privat
 	   return -1;
 	 dht_marker_found = 1;
 	 break;
+       case DRI:
+	 if (parse_DRI(priv, stream) < 0)
+	   return -1;
+	 break;
        default:
 	 trace("> Unknown marker %2.2x\n", marker);
 	 break;
@@ -1812,12 +1890,6 @@ bogus_jpeg_format:
   trace("Bogus jpeg format\n");
   return -1;
 }
-
-/*
- *
- * Export functions
- *
- */
 
 /*******************************************************************************
  *
@@ -2045,6 +2117,17 @@ int tinyjpeg_decode(struct jdec_private 
 	priv->plane[0] += bytes_per_mcu[0];
 	priv->plane[1] += bytes_per_mcu[1];
 	priv->plane[2] += bytes_per_mcu[2];
+	if (priv->restarts_to_go>0)
+	 {
+	   priv->restarts_to_go--;
+	   if (priv->restarts_to_go == 0)
+	    {
+	      priv->stream -= (priv->nbits_in_reservoir/8);
+	      resync(priv);
+	      if (find_next_rst_marker(priv) < 0)
+		return -1;
+	    }
+	 }
       }
    }
 
@@ -2053,6 +2136,8 @@ int tinyjpeg_decode(struct jdec_private 
 
 const char *tinyjpeg_get_errorstring(struct jdec_private *priv)
 {
+  /* FIXME: the error string must be store in the context */
+  priv = priv;
   return error_string;
 }
 



More information about the ekiga-list mailing list