public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
From: Hans de Goede <hdegoede@redhat.com>
To: "Németh Márton" <nm127@freemail.hu>
Cc: Luc Saillard <luc@saillard.org>,
	Thomas Kaiser <v4l@kaiser-linux.li>,
	V4L Mailing List <linux-media@vger.kernel.org>
Subject: Re: [PATCH libv4l tree, RFC] libv4l: skip false Pixart markers with buffer copy
Date: Fri, 05 Feb 2010 14:42:36 +0100	[thread overview]
Message-ID: <4B6C204C.1010407@redhat.com> (raw)
In-Reply-To: <4B6A83A9.4070500@freemail.hu>

Hi,

On 02/04/2010 09:22 AM, Németh Márton wrote:
> Hi,
>
> This is a proof-of-concept patch to try to decode the JPEG with PixArt markers.
>
> Please check whether it is working at your side. My experience is that the
> number of frames with glitch are reduced.
>

Hi,

Good job! I never noticed the ff ff ff xx markers where spaced a certain numbers
of bytes apart. Based on that I've written a different filtering function, which
at least for me completely removes all glitches!!

See:
http://linuxtv.org/hg/~hgoede/libv4l/rev/1fa67e17b77c

Thanks !!!

Regards,

Hans


> Regards,
>
> 	Márton Németh
>
> ---
> From: Márton Németh<nm127@freemail.hu>
>
> Before trying to decode the image data filter the PixArt markers out.
>
> Signed-off-by: Márton Németh<nm127@freemail.hu>
> ---
> diff -r 966f60c672e9 v4l2-apps/libv4l/libv4lconvert/tinyjpeg-internal.h
> --- a/v4l2-apps/libv4l/libv4lconvert/tinyjpeg-internal.h	Tue Feb 02 11:34:06 2010 +0100
> +++ b/v4l2-apps/libv4l/libv4lconvert/tinyjpeg-internal.h	Thu Feb 04 09:13:24 2010 +0100
> @@ -91,8 +91,11 @@
>     /* Private variables */
>     const unsigned char *stream_begin, *stream_end;
>     unsigned int stream_length;
> +  unsigned char *stream_begin_filtered, *stream_end_filtered;
> +  unsigned int stream_length_filtered;
>
>     const unsigned char *stream;	/* Pointer to the current stream */
> +  unsigned char *stream_filtered;
>     unsigned int reservoir, nbits_in_reservoir;
>
>     struct component component_infos[COMPONENTS];
> diff -r 966f60c672e9 v4l2-apps/libv4l/libv4lconvert/tinyjpeg.c
> --- a/v4l2-apps/libv4l/libv4lconvert/tinyjpeg.c	Tue Feb 02 11:34:06 2010 +0100
> +++ b/v4l2-apps/libv4l/libv4lconvert/tinyjpeg.c	Thu Feb 04 09:13:24 2010 +0100
> @@ -312,19 +312,18 @@
>
>   /* Special Pixart versions of the *_nbits functions, these remove the special
>      ff ff ff xx sequences pixart cams insert from the bitstream */
> -#define pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) \
> +#define pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,stream_end,nbits_wanted) \
>   do { \
>      while (nbits_in_reservoir<nbits_wanted) \
>       { \
>         unsigned char c; \
> -      if (stream>= priv->stream_end) { \
> +      if (stream>= stream_end) { \
>   	snprintf(priv->error_string, sizeof(priv->error_string), \
>   	  "fill_nbits error: need %u more bits\n", \
>   	  nbits_wanted - nbits_in_reservoir); \
>   	longjmp(priv->jump_state, -EIO); \
>         } \
>         c = *stream++; \
> -      reservoir<<= 8; \
>         if (c == 0xff) { \
>   	switch (stream[0]) { \
>   	  case 0x00: \
> @@ -332,7 +331,7 @@
>   	    break; \
>   	  case 0xd9: /* EOF marker */ \
>   	    stream++; \
> -	    if (stream != priv->stream_end) { \
> +	    if (stream != stream_end) { \
>   	      snprintf(priv->error_string, sizeof(priv->error_string), \
>   		"Pixart JPEG error: premature EOF\n"); \
>   	      longjmp(priv->jump_state, -EIO); \
> @@ -340,14 +339,22 @@
>   	    break; \
>   	  case 0xff: \
>   	    if (stream[1] == 0xff) { \
> -		if (stream[2]<  7) { \
> +		if (stream[2] == 0) { \
> +		    stream += 3; \
> +		    c = *stream++; \
> +		    break; \
> +		} else if (stream[2] == 1) { \
> +		    stream += 3; \
> +		    c = *stream++; \
> +		    break; \
> +		} else if (stream[2] == 2) { \
>   		    stream += 3; \
>   		    c = *stream++; \
>   		    break; \
>   		} else if (stream[2] == 0xff) { \
> -		    /* four 0xff in a row: the first belongs to the image data */ \
> +		    /* four 0xff in a row: the first belongs to the image */ \
>   		    break; \
> -		}\
> +		} \
>   	    } \
>   	    /* Error fall through */ \
>   	  default: \
> @@ -358,15 +365,16 @@
>   	    longjmp(priv->jump_state, -EIO); \
>   	} \
>         } \
> +      reservoir<<= 8; \
>         reservoir |= c; \
>         nbits_in_reservoir+=8; \
>       } \
>   }  while(0);
>
>   /* Signed version !!!! */
> -#define pixart_get_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) \
> +#define pixart_get_nbits(reservoir,nbits_in_reservoir,stream,stream_end,nbits_wanted,result) \
>   do { \
> -   pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
> +   pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,stream_end,(nbits_wanted)); \
>      result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
>      nbits_in_reservoir -= (nbits_wanted);  \
>      reservoir&= ((1U<<nbits_in_reservoir)-1); \
> @@ -374,9 +382,9 @@
>          result += (0xFFFFFFFFUL<<(nbits_wanted))+1; \
>   }  while(0);
>
> -#define pixart_look_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) \
> +#define pixart_look_nbits(reservoir,nbits_in_reservoir,stream,stream_end,nbits_wanted,result) \
>   do { \
> -   pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
> +   pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,stream_end,(nbits_wanted)); \
>      result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
>   }  while(0);
>
> @@ -443,7 +451,8 @@
>     unsigned int extra_nbits, nbits;
>     uint16_t *slowtable;
>
> -  pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, HUFFMAN_HASH_NBITS, hcode);
> +  pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream_filtered,
> +		    priv->stream_end_filtered, HUFFMAN_HASH_NBITS, hcode);
>     value = huffman_table->lookup[hcode];
>     if (value>= 0)
>     {
> @@ -457,7 +466,8 @@
>      {
>        nbits = HUFFMAN_HASH_NBITS + 1 + extra_nbits;
>
> -     pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits, hcode);
> +     pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream_filtered,
> +			priv->stream_end_filtered, nbits, hcode);
>        slowtable = huffman_table->slowtable[extra_nbits];
>        /* Search if the code is in this array */
>        while (slowtable[0]) {
> @@ -557,7 +567,8 @@
>     /* DC coefficient decoding */
>     huff_code = pixart_get_next_huffman_code(priv, c->DC_table);
>     if (huff_code) {
> -     pixart_get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, huff_code, DCT[0]);
> +     pixart_get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream_filtered,
> +		priv->stream_end_filtered, huff_code, DCT[0]);
>        DCT[0] += c->previous_DC;
>        c->previous_DC = DCT[0];
>     } else {
> @@ -585,7 +596,8 @@
>         {
>   	j += count_0;	/* skip count_0 zeroes */
>   	if (j<  64 ) {
> -	  pixart_get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]);
> +	  pixart_get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream_filtered,
> +			priv->stream_end_filtered, size_val, DCT[j]);
>   	  j++;
>   	}
>         }
> @@ -1611,8 +1623,8 @@
>   {
>     unsigned char marker;
>
> -  pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream,
> -		    8, marker);
> +  pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream_filtered,
> +		    priv->stream_end_filtered, 8, marker);
>     /* I think the marker indicates which quantization table to use, iow
>        a Pixart JPEG may have a different quantization table per MCU, most
>        MCU's have 0x44 as marker for which our special Pixart quantization
> @@ -2342,6 +2354,97 @@
>
>   int tinyjpeg_decode_planar(struct jdec_private *priv, int pixfmt);
>
> +static int memcpy_filter(unsigned char *dest, const unsigned char *src, int n)
> +{
> +	int i = 0;
> +	int j = 0;
> +	int state = 0;
> +	int last_i = 0;
> +
> +	i = 0;
> +	j = 0;
> +
> +	/* 5 bytes are already dropped in kernel: 0xff 0xff 0x00 0xff 0x96 */
> +	/* Copy the rest of 1024 bytes */
> +	memcpy(&(dest[j]),&(src[i]), 1024-5);
> +	i += 1024-5;
> +	j += 1024-5;
> +
> +	while (i<  n) {
> +		switch (state) {
> +			case 0:
> +				if (src[i] == 0xff)
> +					state = 1;
> +				else {
> +					state = 0;
> +					dest[j++] = src[i];
> +				}
> +				break;
> +			case 1:
> +				if (src[i] == 0xff)
> +					state = 2;
> +				else {
> +					state = 0;
> +					dest[j++] = src[i-1];
> +					dest[j++] = src[i];
> +				}
> +				break;
> +			case 2:
> +				switch (src[i]) {
> +					case 0xff:
> +						state = 3;
> +						break;
> +					default:
> +						state = 0;
> +						dest[j++] = src[i-2];
> +						dest[j++] = src[i-1];
> +						dest[j++] = src[i];
> +				}
> +				break;
> +			case 3:
> +				switch (src[i]) {
> +					case 0:
> +						/* found 0xff 0xff 0xff 0x00 */
> +						state = 0;
> +						break;
> +					case 1:
> +						/* found 0xff 0xff 0xff 0x01 */
> +						last_i = i+1;
> +						memcpy(&(dest[j]),&(src[i+1]), 1024);
> +						i += 1024;
> +						j += 1024;
> +						state = 0;
> +						break;
> +					case 2:
> +						/* found 0xff 0xff 0xff 0x02 */
> +						last_i = i+1;
> +						memcpy(&(dest[j]),&(src[i+1]), 512);
> +						i += 512;
> +						j += 512;
> +						state = 0;
> +						break;
> +					case 0xff:
> +						printf(" ! ");
> +						dest[j++] = src[i-3];
> +						state = 3;
> +						break;
> +
> +					default:
> +						state = 0;
> +						dest[j++] = src[i-3];
> +						dest[j++] = src[i-2];
> +						dest[j++] = src[i-1];
> +						dest[j++] = src[i];
> +				
> +				}
> +		}
> +		i++;
> +	}
> +
> +	return j;
> +}
> +
> +
>   /**
>    * Decode and convert the jpeg image into @pixfmt@ image
>    *
> @@ -2356,8 +2459,10 @@
>     const convert_colorspace_fct *colorspace_array_conv;
>     convert_colorspace_fct convert_to_pixfmt;
>
> -  if (setjmp(priv->jump_state))
> +  if (setjmp(priv->jump_state)) {
> +    printf("ERROR: %s\n", priv->error_string);
>       return -1;
> +  }
>
>     if (priv->flags&  TINYJPEG_FLAGS_PLANAR_JPEG)
>       return tinyjpeg_decode_planar(priv, pixfmt);
> @@ -2369,8 +2474,20 @@
>     bytes_per_blocklines[2] = 0;
>
>     decode_mcu_table = decode_mcu_3comp_table;
> -  if (priv->flags&  TINYJPEG_FLAGS_PIXART_JPEG)
> +  if (priv->flags&  TINYJPEG_FLAGS_PIXART_JPEG) {
> +    int len_filtered = 0;
> +
> +    priv->stream_begin_filtered = malloc(priv->stream_end - priv->stream);
> +    if (priv->stream_begin_filtered) {
> +	memset(priv->stream_begin_filtered, 0, priv->stream_end - priv->stream);
> +	priv->stream_filtered = priv->stream_begin_filtered;
> +	len_filtered = memcpy_filter(priv->stream_filtered,
> +			priv->stream, priv->stream_end - priv->stream);
> +    }
> +    priv->stream_end_filtered = priv->stream_filtered + len_filtered;
> +
>       decode_mcu_table = pixart_decode_mcu_3comp_table;
> +  }
>
>     switch (pixfmt) {
>        case TINYJPEG_FMT_YUV420P:
> @@ -2487,8 +2604,12 @@
>
>     if (priv->flags&  TINYJPEG_FLAGS_PIXART_JPEG) {
>       /* Additional sanity check for funky Pixart format */
> -    if ((priv->stream_end - priv->stream)>  5)
> +    if ((priv->stream_end_filtered - priv->stream_filtered)>  5)
>         error("Pixart JPEG error, stream does not end with EOF marker\n");
> +
> +    free(priv->stream_begin_filtered);
> +    priv->stream_filtered = NULL;
> +    priv->stream_end_filtered = NULL;
>     }
>
>     return 0;

  reply	other threads:[~2010-02-05 13:42 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-02-01 21:23 libv4l: possible problem found in PAC7302 JPEG decoding Németh Márton
2010-02-01 22:13 ` [PATCH ] libv4l: skip false Pixart markers Németh Márton
2010-02-02 10:30   ` Hans de Goede
2010-02-02 18:54     ` Németh Márton
2010-02-04  8:22     ` [PATCH libv4l tree, RFC] libv4l: skip false Pixart markers with buffer copy Németh Márton
2010-02-05 13:42       ` Hans de Goede [this message]
2010-02-05 16:43         ` Thomas Kaiser
2010-02-02 10:46 ` libv4l: possible problem found in PAC7302 JPEG decoding Thomas Kaiser
2010-02-02 18:59   ` Németh Márton
2010-02-02 19:48     ` Thomas Kaiser

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B6C204C.1010407@redhat.com \
    --to=hdegoede@redhat.com \
    --cc=linux-media@vger.kernel.org \
    --cc=luc@saillard.org \
    --cc=nm127@freemail.hu \
    --cc=v4l@kaiser-linux.li \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox