From ffc5430bc30a787ae684549df3afcb7b9dcc86d9 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Thu, 26 Oct 2006 04:15:48 +0000 Subject: [PATCH] LZW decoder as separate module plus TIFF LZW support Originally committed as revision 6795 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/Makefile | 4 +- libavcodec/avcodec.h | 4 +- libavcodec/gifdec.c | 176 ++--------------------------- libavcodec/lzw.c | 262 +++++++++++++++++++++++++++++++++++++++++++ libavcodec/lzw.h | 49 ++++++++ libavcodec/tiff.c | 21 +++- 6 files changed, 342 insertions(+), 174 deletions(-) create mode 100644 libavcodec/lzw.c create mode 100644 libavcodec/lzw.h diff --git a/libavcodec/Makefile b/libavcodec/Makefile index e49ee98ced..6fc77c08c0 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -81,7 +81,7 @@ OBJS-$(CONFIG_FLASHSV_DECODER) += flashsv.o OBJS-$(CONFIG_FLIC_DECODER) += flicvideo.o OBJS-$(CONFIG_FOURXM_DECODER) += 4xm.o OBJS-$(CONFIG_FRAPS_DECODER) += fraps.o -OBJS-$(CONFIG_GIF_DECODER) += gifdec.o +OBJS-$(CONFIG_GIF_DECODER) += gifdec.o lzw.o OBJS-$(CONFIG_H261_DECODER) += h261.o OBJS-$(CONFIG_H261_ENCODER) += h261.o OBJS-$(CONFIG_H264_DECODER) += h264.o @@ -132,7 +132,7 @@ OBJS-$(CONFIG_SVQ1_ENCODER) += svq1.o OBJS-$(CONFIG_SVQ3_DECODER) += h264.o OBJS-$(CONFIG_TARGA_DECODER) += targa.o OBJS-$(CONFIG_THEORA_DECODER) += vp3.o -OBJS-$(CONFIG_TIFF_DECODER) += tiff.o +OBJS-$(CONFIG_TIFF_DECODER) += tiff.o lzw.o OBJS-$(CONFIG_TRUEMOTION1_DECODER) += truemotion1.o OBJS-$(CONFIG_TRUEMOTION2_DECODER) += truemotion2.o OBJS-$(CONFIG_TRUESPEECH_DECODER) += truespeech.o diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index dafedbaf1b..2ad9917e94 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -37,8 +37,8 @@ extern "C" { #define AV_STRINGIFY(s) AV_TOSTRING(s) #define AV_TOSTRING(s) #s -#define LIBAVCODEC_VERSION_INT ((51<<16)+(21<<8)+0) -#define LIBAVCODEC_VERSION 51.21.0 +#define LIBAVCODEC_VERSION_INT ((51<<16)+(22<<8)+0) +#define LIBAVCODEC_VERSION 51.22.0 #define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT #define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) diff --git a/libavcodec/gifdec.c b/libavcodec/gifdec.c index 23d023f432..bde483499c 100644 --- a/libavcodec/gifdec.c +++ b/libavcodec/gifdec.c @@ -24,9 +24,7 @@ #include "avcodec.h" #include "bytestream.h" - -#define MAXBITS 12 -#define SIZTABLE (1<eob_reached = 0; - s->pbuf = s->buf; - s->ebuf = s->buf; - s->bbuf = 0; - s->bbits = 0; - - /* decoder */ - s->codesize = csize; - s->cursize = s->codesize + 1; - s->curmask = mask[s->cursize]; - s->top_slot = 1 << s->cursize; - s->clear_code = 1 << s->codesize; - s->end_code = s->clear_code + 1; - s->slot = s->newcodes = s->clear_code + 2; - s->oc = s->fc = 0; - s->sp = s->stack; -} - -/* XXX: optimize */ -static inline int GetCode(GifState * s) -{ - int c, sizbuf; - uint8_t *ptr; - - while (s->bbits < s->cursize) { - ptr = s->pbuf; - if (ptr >= s->ebuf) { - if (!s->eob_reached) { - sizbuf = bytestream_get_byte(&s->bytestream); - s->ebuf = s->buf + sizbuf; - s->pbuf = s->buf; - if (sizbuf > 0) { - bytestream_get_buffer(&s->bytestream, s->buf, sizbuf); - } else { - s->eob_reached = 1; - } - } - ptr = s->pbuf; - } - s->bbuf |= ptr[0] << s->bbits; - ptr++; - s->pbuf = ptr; - s->bbits += 8; - } - c = s->bbuf & s->curmask; - s->bbuf >>= s->cursize; - s->bbits -= s->cursize; - return c; -} - -/* NOTE: the algorithm here is inspired from the LZW GIF decoder - written by Steven A. Bennett in 1987. */ -/* return the number of byte decoded */ -static int GLZWDecode(GifState * s, uint8_t * buf, int len) -{ - int l, c, code, oc, fc; - uint8_t *sp; - - if (s->end_code < 0) - return 0; - - l = len; - sp = s->sp; - oc = s->oc; - fc = s->fc; - - while (sp > s->stack) { - *buf++ = *(--sp); - if ((--l) == 0) - goto the_end; - } - - for (;;) { - c = GetCode(s); - if (c == s->end_code) { - s->end_code = -1; - break; - } else if (c == s->clear_code) { - s->cursize = s->codesize + 1; - s->curmask = mask[s->cursize]; - s->slot = s->newcodes; - s->top_slot = 1 << s->cursize; - while ((c = GetCode(s)) == s->clear_code); - if (c == s->end_code) { - s->end_code = -1; - break; - } - /* test error */ - if (c >= s->slot) - c = 0; - fc = oc = c; - *buf++ = c; - if ((--l) == 0) - break; - } else { - code = c; - if (code >= s->slot) { - *sp++ = fc; - code = oc; - } - while (code >= s->newcodes) { - *sp++ = s->suffix[code]; - code = s->prefix[code]; - } - *sp++ = code; - if (s->slot < s->top_slot) { - s->suffix[s->slot] = fc = code; - s->prefix[s->slot++] = oc; - oc = c; - } - if (s->slot >= s->top_slot) { - if (s->cursize < MAXBITS) { - s->top_slot <<= 1; - s->curmask = mask[++s->cursize]; - } - } - while (sp > s->stack) { - *buf++ = *(--sp); - if ((--l) == 0) - goto the_end; - } - } - } - the_end: - s->sp = sp; - s->oc = oc; - s->fc = fc; - return len - l; -} - static int gif_read_image(GifState *s) { int left, top, width, height, bits_per_pixel, code_size, flags; @@ -267,7 +106,8 @@ static int gif_read_image(GifState *s) /* now get the image data */ code_size = bytestream_get_byte(&s->bytestream); - GLZWDecodeInit(s, code_size); + //TODO: add proper data size + ff_lzw_decode_init(s->lzw, code_size, s->bytestream, 0, FF_LZW_GIF); /* read all the image */ linesize = s->picture.linesize[0]; @@ -276,7 +116,7 @@ static int gif_read_image(GifState *s) pass = 0; y1 = 0; for (y = 0; y < height; y++) { - GLZWDecode(s, ptr, width); + ff_lzw_decode(s->lzw, ptr, width); if (is_interleaved) { switch(pass) { default: @@ -314,8 +154,8 @@ static int gif_read_image(GifState *s) av_free(line); /* read the garbage data until end marker is found */ - while (!s->eob_reached) - GetCode(s); + ff_lzw_decode_tail(s->lzw); + s->bytestream = ff_lzw_cur_ptr(s->lzw); return 0; } @@ -445,6 +285,7 @@ static int gif_decode_init(AVCodecContext *avctx) avcodec_get_frame_defaults(&s->picture); avctx->coded_frame= &s->picture; s->picture.data[0] = NULL; + ff_lzw_decode_open(&s->lzw); return 0; } @@ -483,6 +324,7 @@ static int gif_decode_close(AVCodecContext *avctx) { GifState *s = avctx->priv_data; + ff_lzw_decode_close(&s->lzw); if(s->picture.data[0]) avctx->release_buffer(avctx, &s->picture); return 0; diff --git a/libavcodec/lzw.c b/libavcodec/lzw.c new file mode 100644 index 0000000000..b5bb33a219 --- /dev/null +++ b/libavcodec/lzw.c @@ -0,0 +1,262 @@ +/* + * LZW decoder + * Copyright (c) 2003 Fabrice Bellard. + * Copyright (c) 2006 Konstantin Shishkov. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file lzw.c + * @brief LZW decoding routines + * @author Fabrice Bellard + * Modified for use in TIFF by Konstantin Shishkov + */ + +#include "avcodec.h" +#include "lzw.h" + +#define LZW_MAXBITS 12 +#define LZW_SIZTABLE (1<mode == FF_LZW_GIF) { + while (s->bbits < s->cursize) { + if (!s->bs) { + sizbuf = *s->pbuf++; + s->bs = sizbuf; + if(!sizbuf) { + s->eob_reached = 1; + } + } + s->bbuf |= (*s->pbuf++) << s->bbits; + s->bbits += 8; + s->bs--; + } + c = s->bbuf & s->curmask; + s->bbuf >>= s->cursize; + } else { // TIFF + while (s->bbits < s->cursize) { + if (s->pbuf >= s->ebuf) { + s->eob_reached = 1; + } + s->bbuf = (s->bbuf << 8) | (*s->pbuf++); + s->bbits += 8; + } + c = (s->bbuf >> (s->bbits - s->cursize)) & s->curmask; + } + s->bbits -= s->cursize; + return c; +} + +uint8_t* ff_lzw_cur_ptr(LZWState *p) +{ + return ((struct LZWState*)p)->pbuf; +} + +void ff_lzw_decode_tail(LZWState *p) +{ + struct LZWState *s = (struct LZWState *)p; + while(!s->eob_reached) + lzw_get_code(s); +} + +void ff_lzw_decode_open(LZWState **p) +{ + *p = av_mallocz(sizeof(struct LZWState)); +} + +void ff_lzw_decode_close(LZWState **p) +{ + av_freep(p); +} + +/** + * Initialize LZW decoder + * @param s LZW context + * @param csize initial code size in bits + * @param buf input data + * @param buf_size input data size + * @param mode decoder working mode - either GIF or TIFF + */ +int ff_lzw_decode_init(LZWState *p, int csize, uint8_t *buf, int buf_size, int mode) +{ + struct LZWState *s = (struct LZWState *)p; + + if(csize < 1 || csize > LZW_MAXBITS) + return -1; + /* read buffer */ + s->eob_reached = 0; + s->pbuf = buf; + s->ebuf = s->pbuf + buf_size; + s->bbuf = 0; + s->bbits = 0; + s->bs = 0; + + /* decoder */ + s->codesize = csize; + s->cursize = s->codesize + 1; + s->curmask = mask[s->cursize]; + s->top_slot = 1 << s->cursize; + s->clear_code = 1 << s->codesize; + s->end_code = s->clear_code + 1; + s->slot = s->newcodes = s->clear_code + 2; + s->oc = s->fc = 0; + s->sp = s->stack; + + s->mode = mode; + switch(s->mode){ + case FF_LZW_GIF: + s->top_slot2 = s->top_slot; + break; + case FF_LZW_TIFF: + s->top_slot2 = s->top_slot - 1; + break; + default: + return -1; + } + return 0; +} + +/** + * Decode given number of bytes + * NOTE: the algorithm here is inspired from the LZW GIF decoder + * written by Steven A. Bennett in 1987. + * + * @param s LZW context + * @param buf output buffer + * @param len number of bytes to decode + * @return number of bytes decoded + */ +int ff_lzw_decode(LZWState *p, uint8_t *buf, int len){ + int l, c, code, oc, fc; + uint8_t *sp; + struct LZWState *s = (struct LZWState *)p; + + if (s->end_code < 0) + return 0; + + l = len; + sp = s->sp; + oc = s->oc; + fc = s->fc; + + while (sp > s->stack) { + *buf++ = *(--sp); + if ((--l) == 0) + goto the_end; + } + + for (;;) { + c = lzw_get_code(s); + if (c == s->end_code) { + s->end_code = -1; + break; + } else if (c == s->clear_code) { + s->cursize = s->codesize + 1; + s->curmask = mask[s->cursize]; + s->slot = s->newcodes; + s->top_slot = 1 << s->cursize; + s->top_slot2 = s->top_slot; + if(s->mode == FF_LZW_TIFF) + s->top_slot2--; + while ((c = lzw_get_code(s)) == s->clear_code); + if (c == s->end_code) { + s->end_code = -1; + break; + } + /* test error */ + if (c >= s->slot) + c = 0; + fc = oc = c; + *buf++ = c; + if ((--l) == 0) + break; + } else { + code = c; + if (code >= s->slot) { + *sp++ = fc; + code = oc; + } + while (code >= s->newcodes) { + *sp++ = s->suffix[code]; + code = s->prefix[code]; + } + *sp++ = code; + if (s->slot < s->top_slot) { + s->suffix[s->slot] = fc = code; + s->prefix[s->slot++] = oc; + oc = c; + } + if (s->slot >= s->top_slot2) { + if (s->cursize < LZW_MAXBITS) { + s->top_slot <<= 1; + s->top_slot2 = s->top_slot; + if(s->mode == FF_LZW_TIFF) + s->top_slot2--; + s->curmask = mask[++s->cursize]; + } + } + while (sp > s->stack) { + *buf++ = *(--sp); + if ((--l) == 0) + goto the_end; + } + } + } + the_end: + s->sp = sp; + s->oc = oc; + s->fc = fc; + return len - l; +} diff --git a/libavcodec/lzw.h b/libavcodec/lzw.h new file mode 100644 index 0000000000..60f115caf7 --- /dev/null +++ b/libavcodec/lzw.h @@ -0,0 +1,49 @@ +/* + * LZW decoder + * Copyright (c) 2003 Fabrice Bellard. + * Copyright (c) 2006 Konstantin Shishkov. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file lzw.h + * @brief LZW decoding routines + * @author Fabrice Bellard + * Modified for use in TIFF by Konstantin Shishkov + */ + +#ifndef LZW_H +#define LZW_H + +enum FF_LZW_MODES{ + FF_LZW_GIF, + FF_LZW_TIFF +}; + +/* clients should not know what LZWState is */ +typedef void LZWState; + +/* first two functions de/allocate memory for LZWState */ +void ff_lzw_decode_open(LZWState **p); +void ff_lzw_decode_close(LZWState **p); +int ff_lzw_decode_init(LZWState *s, int csize, uint8_t *buf, int buf_size, int mode); +int ff_lzw_decode(LZWState *s, uint8_t *buf, int len); +uint8_t* ff_lzw_cur_ptr(LZWState *lzw); +void ff_lzw_decode_tail(LZWState *lzw); + +#endif diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c index 41182d0091..57bdc37100 100644 --- a/libavcodec/tiff.c +++ b/libavcodec/tiff.c @@ -23,6 +23,7 @@ #ifdef CONFIG_ZLIB #include #endif +#include "lzw.h" /* abridged list of TIFF tags */ enum TiffTags{ @@ -74,6 +75,7 @@ typedef struct TiffContext { uint8_t* stripdata; uint8_t* stripsizes; int stripsize, stripoff; + LZWState *lzw; } TiffContext; static int tget_short(uint8_t **p, int le){ @@ -126,6 +128,12 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t* dst, int stride, uint8_t * return 0; } #endif + if(s->compr == TIFF_LZW){ + if(ff_lzw_decode_init(s->lzw, 8, src, size, FF_LZW_TIFF) < 0){ + av_log(s->avctx, AV_LOG_ERROR, "Error initializing LZW decoder\n"); + return -1; + } + } for(line = 0; line < lines; line++){ if(src - ssrc > size){ av_log(s->avctx, AV_LOG_ERROR, "Source data overread\n"); @@ -160,6 +168,13 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t* dst, int stride, uint8_t * } } break; + case TIFF_LZW: + pixels = ff_lzw_decode(s->lzw, dst, width); + if(pixels < width){ + av_log(s->avctx, AV_LOG_ERROR, "Decoded only %i bytes of %i\n", pixels, width); + return -1; + } + break; } dst += stride; } @@ -247,6 +262,7 @@ static int tiff_decode_tag(TiffContext *s, uint8_t *start, uint8_t *buf, uint8_t switch(s->compr){ case TIFF_RAW: case TIFF_PACKBITS: + case TIFF_LZW: break; case TIFF_DEFLATE: case TIFF_ADOBE_DEFLATE: @@ -256,9 +272,6 @@ static int tiff_decode_tag(TiffContext *s, uint8_t *start, uint8_t *buf, uint8_t av_log(s->avctx, AV_LOG_ERROR, "Deflate: ZLib not compiled in\n"); return -1; #endif - case TIFF_LZW: - av_log(s->avctx, AV_LOG_ERROR, "LZW: not implemented yet\n"); - return -1; case TIFF_G3: av_log(s->avctx, AV_LOG_ERROR, "CCITT G3 compression is not supported\n"); return -1; @@ -405,6 +418,7 @@ static int tiff_init(AVCodecContext *avctx){ avcodec_get_frame_defaults((AVFrame*)&s->picture); avctx->coded_frame= (AVFrame*)&s->picture; s->picture.data[0] = NULL; + ff_lzw_decode_open(&s->lzw); return 0; } @@ -413,6 +427,7 @@ static int tiff_end(AVCodecContext *avctx) { TiffContext * const s = avctx->priv_data; + ff_lzw_decode_close(&s->lzw); if(s->picture.data[0]) avctx->release_buffer(avctx, &s->picture); return 0;