The patch number 14259 was added via h...@rhel5-devel.localdomain to http://linuxtv.org/hg/v4l-dvb master development tree.
Kernel patches in this development tree may be modified to be backward compatible with older kernels. Compatibility modifications will be removed before inclusion into the mainstream Kernel If anyone has any objections, please let us know by sending a message to: Linux Media Mailing List <linux-me...@vger.kernel.org> ------ From: Hans de Goede <hdego...@redhat.com> libv4l: Add support for decompressing yuv420 planar JPEG Add support for decompressing yuv420 planar JPEG (one component per SOS, 3 SOS per frame) Priority: normal Signed-off-by: Hans de Goede <hdego...@redhat.com> --- v4l2-apps/libv4l/ChangeLog | 2 v4l2-apps/libv4l/libv4lconvert/tinyjpeg-internal.h | 7 v4l2-apps/libv4l/libv4lconvert/tinyjpeg.c | 302 ++++++++++++- v4l2-apps/libv4l/libv4lconvert/tinyjpeg.h | 1 4 files changed, 309 insertions(+), 3 deletions(-) diff -r c07ce4df6d6c -r 555cfef23705 v4l2-apps/libv4l/ChangeLog --- a/v4l2-apps/libv4l/ChangeLog Fri Oct 16 08:34:43 2009 +0200 +++ b/v4l2-apps/libv4l/ChangeLog Sun Oct 18 00:40:10 2009 +0200 @@ -2,6 +2,8 @@ ------------ * Add more laptop models to the upside down devices table * Improved mr97310a decompression +* Add support for decompressing yuv420 planar JPEG (one component per SOS, + 3 SOS per frame) libv4l-0.6.2 ------------ diff -r c07ce4df6d6c -r 555cfef23705 v4l2-apps/libv4l/libv4lconvert/tinyjpeg-internal.h --- a/v4l2-apps/libv4l/libv4lconvert/tinyjpeg-internal.h Fri Oct 16 08:34:43 2009 +0200 +++ b/v4l2-apps/libv4l/libv4lconvert/tinyjpeg-internal.h Sun Oct 18 00:40:10 2009 +0200 @@ -103,6 +103,9 @@ int restart_interval; int restarts_to_go; /* MCUs left in this restart interval */ int last_rst_marker_seen; /* Rst marker is incremented each time */ +#if SANITY_CHECK + unsigned int current_cid; /* For planar JPEG */ +#endif /* Temp space used after the IDCT to store each components */ uint8_t Y[64*4], Cr[64], Cb[64]; @@ -112,6 +115,10 @@ uint8_t *plane[COMPONENTS]; char error_string[256]; + + /* Temp buffers for multipass planar JPG -> RGB decoding */ + int tmp_buf_y_size; + uint8_t *tmp_buf[COMPONENTS]; }; #define IDCT tinyjpeg_idct_float diff -r c07ce4df6d6c -r 555cfef23705 v4l2-apps/libv4l/libv4lconvert/tinyjpeg.c --- a/v4l2-apps/libv4l/libv4lconvert/tinyjpeg.c Fri Oct 16 08:34:43 2009 +0200 +++ b/v4l2-apps/libv4l/libv4lconvert/tinyjpeg.c Sun Oct 18 00:40:10 2009 +0200 @@ -1910,14 +1910,37 @@ trace("> SOS marker\n"); #if SANITY_CHECK - if (nr_components != 3) + if (nr_components != 3 && nr_components != 1) error("We only support YCbCr image\n"); #endif + if (nr_components == 1) + priv->flags |= TINYJPEG_FLAGS_PLANAR_JPEG; +#if SANITY_CHECK + else if (priv->flags & TINYJPEG_FLAGS_PLANAR_JPEG) + error("SOS with more then 1 component while decoding planar JPEG\n"); +#endif + stream += 3; for (i=0;i<nr_components;i++) { cid = *stream++; table = *stream++; + if (nr_components == 1) { +#if SANITY_CHECK + /* Find matching cid so we store the tables in the right component */ + for (i = 0; i < COMPONENTS; i++) + if (priv->component_infos[i].cid == cid) + break; + + if (i == COMPONENTS) + error("Unknown cid in SOS: %u\n", cid); + + priv->current_cid = cid; +#else + i = cid - 1; +#endif + trace("SOS cid: %u, using component_info: %u\n", cid, i); + } #if SANITY_CHECK if ((table&0xf) >= HUFFMAN_TABLES) error("We do not support more than %d AC Huffman table\n", @@ -2048,7 +2071,11 @@ } /* Skip any padding ff byte (this is normal) */ while (*stream == 0xff) + { stream++; + if (stream >= priv->stream_end) + error("EOF while search for a RST marker.\n"); + } marker = *stream++; if ((RST+priv->last_rst_marker_seen) == marker) @@ -2066,6 +2093,32 @@ return 0; } +static int find_next_sos_marker(struct jdec_private *priv) +{ + const unsigned char *stream = priv->stream; + + /* Parse marker */ + while (1) { + while (*stream++ != 0xff) { + if (stream >= priv->stream_end) + error("EOF while search for a SOS marker.\n"); + } + /* Skip any padding ff byte (this is normal) */ + while (*stream == 0xff) { + stream++; + if (stream >= priv->stream_end) + error("EOF while search for a SOS marker.\n"); + } + + if (*stream++ == SOS) + break; /* Found it ! */ + } + + priv->stream = stream; + + return 0; +} + static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream) { int chuck_len; @@ -2154,6 +2207,10 @@ || (priv->component_infos[cCb].Vfactor!=1) || (priv->component_infos[cCr].Vfactor!=1)) error("Sampling other than 1x1 for Cr and Cb is not supported\n"); + if ((priv->flags & TINYJPEG_FLAGS_PLANAR_JPEG) && + ( (priv->component_infos[cY].Hfactor!=2) + || (priv->component_infos[cY].Hfactor!=2))) + error("Sampling other than 2x2 for Y is not supported with planar JPEG\n"); #endif return 0; @@ -2197,10 +2254,12 @@ { int i; for (i=0; i<COMPONENTS; i++) { - if (priv->components[i]) - free(priv->components[i]); + free(priv->components[i]); + free(priv->tmp_buf[i]); priv->components[i] = NULL; + priv->tmp_buf[i] = NULL; } + priv->tmp_buf_y_size = 0; free(priv); } @@ -2276,6 +2335,8 @@ YCrCB_to_Grey_2x2, }; +int tinyjpeg_decode_planar(struct jdec_private *priv, int pixfmt); + /** * Decode and convert the jpeg image into @pixfmt@ image * @@ -2293,6 +2354,9 @@ if (setjmp(priv->jump_state)) return -1; + if (priv->flags & TINYJPEG_FLAGS_PLANAR_JPEG) + return tinyjpeg_decode_planar(priv, pixfmt); + /* To keep gcc happy initialize some array */ bytes_per_mcu[1] = 0; bytes_per_mcu[2] = 0; @@ -2425,6 +2489,238 @@ return 0; } +int tinyjpeg_decode_planar(struct jdec_private *priv, int pixfmt) +{ + unsigned int i, x, y; + uint8_t *y_buf, *u_buf, *v_buf, *p, *p2; + + switch (pixfmt) { + case TINYJPEG_FMT_GREY: + error("Greyscale output not supported with planar JPEG input\n"); + break; + + case TINYJPEG_FMT_RGB24: + case TINYJPEG_FMT_BGR24: + if (priv->tmp_buf_y_size < (priv->width * priv->height)) { + for (i=0; i<COMPONENTS; i++) { + free(priv->tmp_buf[i]); + priv->tmp_buf[i] = malloc(priv->width * priv->height / (i ? 4:1)); + if (!priv->tmp_buf[i]) + error("Could not allocate memory for temporary buffers\n"); + } + priv->tmp_buf_y_size = priv->width * priv->height; + } + y_buf = priv->tmp_buf[cY]; + u_buf = priv->tmp_buf[cCb]; + v_buf = priv->tmp_buf[cCr]; + break; + + case TINYJPEG_FMT_YUV420P: + y_buf = priv->components[cY]; + u_buf = priv->components[cCb]; + v_buf = priv->components[cCr]; + break; + + default: + error("Bad pixel format\n"); + } + +#if SANITY_CHECK + if (priv->current_cid != priv->component_infos[cY].cid) + error("Planar jpeg first SOS cid does not match Y cid (%u:%u)\n", + priv->current_cid, priv->component_infos[cY].cid); +#endif + + resync(priv); + + for (y=0; y < priv->height/8; y++) { + for (x=0; x < priv->width/8; x++) { + process_Huffman_data_unit(priv, cY); + IDCT(&priv->component_infos[cY], y_buf, priv->width); + y_buf += 8; + } + y_buf += 7 * priv->width; + } + + priv->stream -= (priv->nbits_in_reservoir/8); + resync(priv); + if (find_next_sos_marker(priv) < 0) + return -1; + if (parse_SOS(priv, priv->stream) < 0) + return -1; + +#if SANITY_CHECK + if (priv->current_cid != priv->component_infos[cCb].cid) + error("Planar jpeg second SOS cid does not match Cn cid (%u:%u)\n", + priv->current_cid, priv->component_infos[cCb].cid); +#endif + + for (y=0; y < priv->height/16; y++) { + for (x=0; x < priv->width/16; x++) { + process_Huffman_data_unit(priv, cCb); + IDCT(&priv->component_infos[cCb], u_buf, priv->width / 2); + u_buf += 8; + } + u_buf += 7 * (priv->width / 2); + } + + priv->stream -= (priv->nbits_in_reservoir/8); + resync(priv); + if (find_next_sos_marker(priv) < 0) + return -1; + if (parse_SOS(priv, priv->stream) < 0) + return -1; + +#if SANITY_CHECK + if (priv->current_cid != priv->component_infos[cCr].cid) + error("Planar jpeg third SOS cid does not match Cr cid (%u:%u)\n", + priv->current_cid, priv->component_infos[cCr].cid); +#endif + + for (y=0; y < priv->height/16; y++) { + for (x=0; x < priv->width/16; x++) { + process_Huffman_data_unit(priv, cCr); + IDCT(&priv->component_infos[cCr], v_buf, priv->width / 2); + v_buf += 8; + } + v_buf += 7 * (priv->width / 2); + } + +#define SCALEBITS 10 +#define ONE_HALF (1UL << (SCALEBITS-1)) +#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) + + switch (pixfmt) { + case TINYJPEG_FMT_RGB24: + y_buf = priv->tmp_buf[cY]; + u_buf = priv->tmp_buf[cCb]; + v_buf = priv->tmp_buf[cCr]; + p = priv->components[0]; + p2 = priv->components[0] + priv->width * 3; + + for (y = 0; y < priv->height / 2; y++) { + for (x = 0; x < priv->width / 2; x++) { + int l, cb, cr; + int add_r, add_g, add_b; + int r, g , b; + + cb = *u_buf++ - 128; + cr = *v_buf++ - 128; + add_r = FIX(1.40200) * cr + ONE_HALF; + add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; + add_b = FIX(1.77200) * cb + ONE_HALF; + + l = (*y_buf) << SCALEBITS; + r = (l + add_r) >> SCALEBITS; + *p++ = clamp(r); + g = (l + add_g) >> SCALEBITS; + *p++ = clamp(g); + b = (l + add_b) >> SCALEBITS; + *p++ = clamp(b); + + l = (y_buf[priv->width]) << SCALEBITS; + r = (l + add_r) >> SCALEBITS; + *p2++ = clamp(r); + g = (l + add_g) >> SCALEBITS; + *p2++ = clamp(g); + b = (l + add_b) >> SCALEBITS; + *p2++ = clamp(b); + + y_buf++; + + l = (*y_buf) << SCALEBITS; + r = (l + add_r) >> SCALEBITS; + *p++ = clamp(r); + g = (l + add_g) >> SCALEBITS; + *p++ = clamp(g); + b = (l + add_b) >> SCALEBITS; + *p++ = clamp(b); + + l = (y_buf[priv->width]) << SCALEBITS; + r = (l + add_r) >> SCALEBITS; + *p2++ = clamp(r); + g = (l + add_g) >> SCALEBITS; + *p2++ = clamp(g); + b = (l + add_b) >> SCALEBITS; + *p2++ = clamp(b); + + y_buf++; + } + y_buf += priv->width; + p += priv->width * 3; + p2 += priv->width * 3; + } + break; + + case TINYJPEG_FMT_BGR24: + y_buf = priv->tmp_buf[cY]; + u_buf = priv->tmp_buf[cCb]; + v_buf = priv->tmp_buf[cCr]; + p = priv->components[0]; + p2 = priv->components[0] + priv->width * 3; + + for (y = 0; y < priv->height / 2; y++) { + for (x = 0; x < priv->width / 2; x++) { + int l, cb, cr; + int add_r, add_g, add_b; + int r, g , b; + + cb = *u_buf++ - 128; + cr = *v_buf++ - 128; + add_r = FIX(1.40200) * cr + ONE_HALF; + add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; + add_b = FIX(1.77200) * cb + ONE_HALF; + + l = (*y_buf) << SCALEBITS; + b = (l + add_b) >> SCALEBITS; + *p++ = clamp(b); + g = (l + add_g) >> SCALEBITS; + *p++ = clamp(g); + r = (l + add_r) >> SCALEBITS; + *p++ = clamp(r); + + l = (y_buf[priv->width]) << SCALEBITS; + b = (l + add_b) >> SCALEBITS; + *p2++ = clamp(b); + g = (l + add_g) >> SCALEBITS; + *p2++ = clamp(g); + r = (l + add_r) >> SCALEBITS; + *p2++ = clamp(r); + + y_buf++; + + l = (*y_buf) << SCALEBITS; + b = (l + add_b) >> SCALEBITS; + *p++ = clamp(b); + g = (l + add_g) >> SCALEBITS; + *p++ = clamp(g); + r = (l + add_r) >> SCALEBITS; + *p++ = clamp(r); + + l = (y_buf[priv->width]) << SCALEBITS; + b = (l + add_b) >> SCALEBITS; + *p2++ = clamp(b); + g = (l + add_g) >> SCALEBITS; + *p2++ = clamp(g); + r = (l + add_r) >> SCALEBITS; + *p2++ = clamp(r); + + y_buf++; + } + y_buf += priv->width; + p += priv->width * 3; + p2 += priv->width * 3; + } + break; + } + +#undef SCALEBITS +#undef ONE_HALF +#undef FIX + + return 0; +} + const char *tinyjpeg_get_errorstring(struct jdec_private *priv) { return priv->error_string; diff -r c07ce4df6d6c -r 555cfef23705 v4l2-apps/libv4l/libv4lconvert/tinyjpeg.h --- a/v4l2-apps/libv4l/libv4lconvert/tinyjpeg.h Fri Oct 16 08:34:43 2009 +0200 +++ b/v4l2-apps/libv4l/libv4lconvert/tinyjpeg.h Sun Oct 18 00:40:10 2009 +0200 @@ -44,6 +44,7 @@ /* Flags that can be set by any applications */ #define TINYJPEG_FLAGS_MJPEG_TABLE (1<<1) #define TINYJPEG_FLAGS_PIXART_JPEG (1<<2) +#define TINYJPEG_FLAGS_PLANAR_JPEG (1<<3) /* Format accepted in outout */ enum tinyjpeg_fmt { --- Patch is available at: http://linuxtv.org/hg/v4l-dvb/rev/555cfef2370552887c386b826084146b78808d3a _______________________________________________ linuxtv-commits mailing list linuxtv-commits@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits