[FFmpeg-devel] [PATCH] CCITT Group 3 and 4 decompression

Kostya kostya.shishkov
Thu Dec 25 07:19:25 CET 2008


On Wed, Dec 24, 2008 at 11:00:08PM +0100, Michael Niedermayer wrote:
> On Wed, Dec 24, 2008 at 08:06:13AM +0200, Kostya wrote:
> > On Tue, Dec 23, 2008 at 08:27:31PM +0100, Michael Niedermayer wrote:
> > > On Tue, Dec 23, 2008 at 09:00:57AM +0200, Kostya wrote:
> > > > On Mon, Dec 22, 2008 at 09:06:37PM +0100, Michael Niedermayer wrote:
> > > > > On Mon, Dec 22, 2008 at 08:15:06PM +0200, Kostya wrote:
> > > > > > On Mon, Dec 22, 2008 at 01:13:53PM +0100, Michael Niedermayer wrote:
> > > > > > > On Mon, Dec 22, 2008 at 08:31:55AM +0200, Kostya wrote:
> > > > > > > > I need that for resolving issue 750 on roundup.
[...]
> 
> > +static int decode_group3_1d_line(AVCodecContext *avctx, GetBitContext *gb,
> > +                                 int pix_left, int *runs)
> > +{
> > +    int mode = 0, run = 0;
> > +    unsigned int t;
> 
> > +    while(pix_left){
> 
> first check
> 
> > +        t = get_vlc2(gb, ccitt_vlc[mode].table, 9, 2);
> > +        run += t;
> 
> > +        if(t < 64){
> 
> second check
> 
> 
> > +            pix_left -= run;
> 
> > +            if(pix_left < 0){
> 
> third check
> 
> thats still 1 more than needed
 
not it's one less
 
> [...]
> > +
> > +static void put_line(uint8_t *dst, int size, int width, const int *runs)
> > +{
> > +    PutBitContext pb;
> > +    int run, mode = 0, pix_left = width, run_idx = 0;
> > +
> > +    init_put_bits(&pb, dst, size*8);
> > +    if(!runs[0]){
> > +        run_idx++;
> > +        mode = !mode;
> > +    }
> 
> > +    while(pix_left > 0){
> > +        run = runs[run_idx++];
> > +        if(!run || run_idx >= width)
> > +            return;
> 
> how can run_idx >= width happen here?

dropped out 
 
> > +        pix_left -= run;
> > +        for(; run > 16; run -= 16)
> > +            put_sbits(&pb, 16, -mode);
> > +        put_sbits(&pb, run, -mode);
> > +        mode = !mode;
> > +    }
> > +}
> > +
> 
> > +static int find_group3_syncmarker(GetBitContext *gb, int srcsize)
> > +{
> > +    int state = get_bits(gb, 12);
> > +    int rem = srcsize - get_bits_count(gb);
> > +    while((state & 0xFFF) != 1){
> > +        state = (state << 1) | get_bits1(gb);
> > +        if(--rem <= 0)
> > +            return -1;
> > +    }
> > +    return 0;
> > +}
> 
> you only need 1 get_bits call in this function
> besides this code is buggy, it will miss the sync code when its at
> the end, that is it will never check the last read bit
> Ive already provided a working implementation, why dont you use it?

In most cases EOL will follow line data immediately, so the loop won't
be entered at all instead of 12 iterations in your case. Also it does
not matter for decoding if there's EOL right one bit before line end -
there won't be sufficient data to decode that line anyway (for 2d-case
that single bit is read to determine line coding mode and for 1d case
first codeword should have length >= 4 bits).
 
> > +
> > +int ff_ccitt_unpack_group3_1d(AVCodecContext *avctx,
> > +                              const uint8_t *src, int srcsize,
> > +                              uint8_t *dst, int height, int stride)
> > +{
> > +    int j;
> > +    GetBitContext gb;
> > +    int *runs;
> > +
> > +    runs = av_malloc(avctx->width * sizeof(runs[0]));
> > +    init_get_bits(&gb, src, srcsize*8);
> > +    for(j = 0; j < height; j++){
> > +        if(find_group3_syncmarker(&gb, srcsize*8) < 0)
> > +            break;
> > +        if(decode_group3_1d_line(avctx, &gb, avctx->width, runs) < 0){
> > +            av_log(avctx, AV_LOG_ERROR, "Error decoding line\n");
> > +            continue;
> > +        }
> > +        put_line(dst, stride, avctx->width, runs);
> > +        dst += stride;
> > +    }
> 
> the code should ideally duplicate the last good line for broken lines instead
> of loosing lines.

why not? done 
 
> > +    av_free(runs);
> > +    return 0;
> > +}
> > +
> 
> > +static int ccitt_unpack2d(AVCodecContext *avctx,
> > +                          const uint8_t *src, int srcsize,
> > +                          uint8_t *dst, int height, int stride,
> > +                          int g4)
> > +{
> > +    int j;
> > +    GetBitContext gb;
> > +    int *runs, *ref;
> > +    int ret;
> > +
> > +    runs = av_malloc((avctx->width + 1) * sizeof(runs[0]));
> > +    ref  = av_malloc((avctx->width + 1) * sizeof(ref[0]));
> > +    runs[0] = 0;
> > +    ref[0] = 0;
> > +    ref[1] = avctx->width;
> > +    init_get_bits(&gb, src, srcsize*8);
> > +    for(j = 0; j < height; j++){
> 
> > +        if(g4){
> > +            ret = decode_group3_2d_line(avctx, &gb, avctx->width, runs + 1, ref);
> > +        }else{
> > +            if(find_group3_syncmarker(&gb, srcsize*8) < 0)
> > +                break;
> > +            if(get_bits1(&gb))
> > +                ret = decode_group3_1d_line(avctx, &gb, avctx->width, runs + 1);
> > +            else
> > +                ret = decode_group3_2d_line(avctx, &gb, avctx->width, runs + 1, ref);
> > +        }
> > +        if(ret < 0 && g4){
> > +            av_free(runs);
> > +            av_free(ref);
> > +            return -1;
> > +        }
> 
> this ret<0 check can be simplified by moving it under the if(g4) above

done 
 
> > +        put_line(dst, stride, avctx->width, runs + 1);
> > +        FFSWAP(int*, runs, ref);
> > +        dst += stride;
> > +    }
> 
> this is missing an error message, ff_ccitt_unpack_group3_1d() prints one ...

no need to print it at all 
 
> > +    av_free(runs);
> > +    av_free(ref);
> > +    return 0;
> > +}
> > +
> 
> > +int ff_ccitt_unpack_group3_2d(AVCodecContext *avctx,
> > +                              const uint8_t *src, int srcsize,
> > +                              uint8_t *dst, int height, int stride)
> > +{
> > +    return ccitt_unpack2d(avctx, src, srcsize, dst, height, stride, 0);
> > +}
> > +
> > +int ff_ccitt_unpack_group4(AVCodecContext *avctx,
> > +                           const uint8_t *src, int srcsize,
> > +                           uint8_t *dst, int height, int stride)
> > +{
> > +    return ccitt_unpack2d(avctx, src, srcsize, dst, height, stride, 1);
> > +}
> 
> useless wraper functions

removed
 
> btw, do you have some url where i can find files to test this code?

http://samples.mplayerhq.hu/image-samples/tiff/
 
> PS: merry christmas :)

Well, I live in a country where church calendar uses incorrect rounding
and was tied to the standard one only in XXth century with 13 days of difference
we have New Year first, then Christmas on Jan 7th and then Old New Year on
Jan 14th (i.e.  New Year in Old calendar). Pretty amusing, eh?

Merry Christmas to you though.

> [...]
> -- 
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
-------------- next part --------------
Index: libavcodec/Makefile
===================================================================
--- libavcodec/Makefile	(revision 15993)
+++ libavcodec/Makefile	(working copy)
@@ -201,7 +201,7 @@
 OBJS-$(CONFIG_THEORA_DECODER)          += vp3.o xiph.o vp3dsp.o
 OBJS-$(CONFIG_THP_DECODER)             += mjpegdec.o mjpeg.o
 OBJS-$(CONFIG_TIERTEXSEQVIDEO_DECODER) += tiertexseqv.o
-OBJS-$(CONFIG_TIFF_DECODER)            += tiff.o lzw.o
+OBJS-$(CONFIG_TIFF_DECODER)            += tiff.o lzw.o faxcompr.o
 OBJS-$(CONFIG_TIFF_ENCODER)            += tiffenc.o rle.o lzwenc.o
 OBJS-$(CONFIG_TRUEMOTION1_DECODER)     += truemotion1.o
 OBJS-$(CONFIG_TRUEMOTION2_DECODER)     += truemotion2.o
Index: libavcodec/tiff.c
===================================================================
--- libavcodec/tiff.c	(revision 16268)
+++ libavcodec/tiff.c	(working copy)
@@ -30,6 +30,7 @@
 #endif
 #include "lzw.h"
 #include "tiff.h"
+#include "faxcompr.h"
 
 
 typedef struct TiffContext {
@@ -41,6 +42,7 @@
     int le;
     int compr;
     int invert;
+    int fax_opts;
     int predictor;
 
     int strips, rps, sstype;
@@ -103,6 +105,26 @@
             return -1;
         }
     }
+    if(s->compr == TIFF_CCITT_RLE || s->compr == TIFF_G3 || s->compr == TIFF_G4){
+        int i, ret = 0;
+        uint8_t *src2 = av_malloc(size);
+
+        for(i = 0; i < size; i++)
+            src2[i] = ff_reverse[src[i]];
+        if(s->compr == TIFF_G3 && !(s->fax_opts & 1))
+            s->compr = TIFF_CCITT_RLE;
+        switch(s->compr){
+        case TIFF_CCITT_RLE:
+            ret = ff_ccitt_unpack_1d(s->avctx, src2, size, dst, lines, stride);
+            break;
+        case TIFF_G3:
+        case TIFF_G4:
+            ret = ff_ccitt_unpack_2d(s->avctx, src2, size, dst, lines, stride, s->compr == TIFF_G4);
+            break;
+        }
+        av_free(src2);
+        return ret;
+    }
     for(line = 0; line < lines; line++){
         if(src - ssrc > size){
             av_log(s->avctx, AV_LOG_ERROR, "Source data overread\n");
@@ -265,7 +287,12 @@
         case TIFF_RAW:
         case TIFF_PACKBITS:
         case TIFF_LZW:
+        case TIFF_CCITT_RLE:
             break;
+        case TIFF_G3:
+        case TIFF_G4:
+            s->fax_opts = 0;
+            break;
         case TIFF_DEFLATE:
         case TIFF_ADOBE_DEFLATE:
 #ifdef CONFIG_ZLIB
@@ -274,15 +301,6 @@
             av_log(s->avctx, AV_LOG_ERROR, "Deflate: ZLib not compiled in\n");
             return -1;
 #endif
-        case TIFF_G3:
-            av_log(s->avctx, AV_LOG_ERROR, "CCITT G3 compression is not supported\n");
-            return -1;
-        case TIFF_G4:
-            av_log(s->avctx, AV_LOG_ERROR, "CCITT G4 compression is not supported\n");
-            return -1;
-        case TIFF_CCITT_RLE:
-            av_log(s->avctx, AV_LOG_ERROR, "CCITT RLE compression is not supported\n");
-            return -1;
         case TIFF_JPEG:
         case TIFF_NEWJPEG:
             av_log(s->avctx, AV_LOG_ERROR, "JPEG compression is not supported\n");
@@ -373,6 +391,10 @@
             return -1;
         }
         break;
+    case TIFF_T4OPTIONS:
+    case TIFF_T6OPTIONS:
+        s->fax_opts = value;
+        break;
     }
     return 0;
 }
@@ -487,6 +509,7 @@
     avctx->coded_frame= (AVFrame*)&s->picture;
     s->picture.data[0] = NULL;
     ff_lzw_decode_open(&s->lzw);
+    ff_ccitt_unpack_init();
 
     return 0;
 }
Index: libavcodec/faxcompr.h
===================================================================
--- libavcodec/faxcompr.h	(revision 0)
+++ libavcodec/faxcompr.h	(revision 0)
@@ -0,0 +1,51 @@
+/*
+ * CCITT Fax Group 3 and 4 decompression
+ * Copyright (c) 2008 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
+ */
+
+/**
+ * CCITT Fax Group 3 and 4 decompression
+ * @file faxcompr.h
+ * @author Konstantin Shishkov
+ */
+#ifndef AVCODEC_FAXCOMPR_H
+#define AVCODEC_FAXCOMPR_H
+
+#include "avcodec.h"
+
+/**
+ * initialize upacker code
+ */
+void ff_ccitt_unpack_init();
+
+/**
+ * unpack data compressed with CCITT Group 3 1-D method
+ */
+int ff_ccitt_unpack_1d(AVCodecContext *avctx,
+                       const uint8_t *src, int srcsize,
+                       uint8_t *dst, int height, int stride);
+
+/**
+ * unpack data compressed with CCITT Group 3 2-D or Group 4 method
+ */
+int ff_ccitt_unpack_2d(AVCodecContext *avctx,
+                       const uint8_t *src, int srcsize,
+                       uint8_t *dst, int height, int stride, int g4);
+
+#endif /* AVCODEC_FAXCOMPR_H */
Index: libavcodec/faxcompr.c
===================================================================
--- libavcodec/faxcompr.c	(revision 0)
+++ libavcodec/faxcompr.c	(revision 0)
@@ -0,0 +1,323 @@
+/*
+ * CCITT Fax Group 3 and 4 decompression
+ * Copyright (c) 2008 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
+ */
+
+/**
+ * CCITT Fax Group 3 and 4 decompression
+ * @file faxcompr.c
+ * @author Konstantin Shishkov
+ */
+#include "avcodec.h"
+#include "bitstream.h"
+#include "faxcompr.h"
+
+#define CCITT_SYMS 104
+
+static const uint16_t ccitt_syms[CCITT_SYMS] = {
+    0,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,
+   13,   14,   15,   16,   17,   18,   19,   20,   21,   22,   23,   24,   25,
+   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,   37,   38,
+   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,
+   52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,   64,
+  128,  192,  256,  320,  384,  448,  512,  576,  640,  704,  768,  832,  896,
+  960, 1024, 1088, 1152, 1216, 1280, 1344, 1408, 1472, 1536, 1600, 1664, 1728,
+ 1792, 1856, 1920, 1984, 2048, 2112, 2176, 2240, 2304, 2368, 2432, 2496, 2560
+};
+
+static const uint8_t ccitt_codes_bits[2][CCITT_SYMS] =
+{
+  {
+    0x35, 0x07, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, 0x13, 0x14, 0x07, 0x08, 0x08,
+    0x03, 0x34, 0x35, 0x2A, 0x2B, 0x27, 0x0C, 0x08, 0x17, 0x03, 0x04, 0x28, 0x2B,
+    0x13, 0x24, 0x18, 0x02, 0x03, 0x1A, 0x1B, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+    0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x04, 0x05, 0x0A, 0x0B, 0x52, 0x53, 0x54,
+    0x55, 0x24, 0x25, 0x58, 0x59, 0x5A, 0x5B, 0x4A, 0x4B, 0x32, 0x33, 0x34, 0x1B,
+    0x12, 0x17, 0x37, 0x36, 0x37, 0x64, 0x65, 0x68, 0x67, 0xCC, 0xCD, 0xD2, 0xD3,
+    0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0x98, 0x99, 0x9A, 0x18, 0x9B,
+    0x08, 0x0C, 0x0D, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x1C, 0x1D, 0x1E, 0x1F
+  },
+  {
+    0x37, 0x02, 0x03, 0x02, 0x03, 0x03, 0x02, 0x03, 0x05, 0x04, 0x04, 0x05, 0x07,
+    0x04, 0x07, 0x18, 0x17, 0x18, 0x08, 0x67, 0x68, 0x6C, 0x37, 0x28, 0x17, 0x18,
+    0xCA, 0xCB, 0xCC, 0xCD, 0x68, 0x69, 0x6A, 0x6B, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+    0xD7, 0x6C, 0x6D, 0xDA, 0xDB, 0x54, 0x55, 0x56, 0x57, 0x64, 0x65, 0x52, 0x53,
+    0x24, 0x37, 0x38, 0x27, 0x28, 0x58, 0x59, 0x2B, 0x2C, 0x5A, 0x66, 0x67, 0x0F,
+    0xC8, 0xC9, 0x5B, 0x33, 0x34, 0x35, 0x6C, 0x6D, 0x4A, 0x4B, 0x4C, 0x4D, 0x72,
+    0x73, 0x74, 0x75, 0x76, 0x77, 0x52, 0x53, 0x54, 0x55, 0x5A, 0x5B, 0x64, 0x65,
+    0x08, 0x0C, 0x0D, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x1C, 0x1D, 0x1E, 0x1F
+  }
+};
+
+static const uint8_t ccitt_codes_lens[2][CCITT_SYMS] =
+{
+  {
+     8,  6,  4,  4,  4,  4,  4,  4,  5,  5,  5,  5,  6,  6,  6,  6,  6,  6,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+     8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+     8,  8,  8,  8,  5,  5,  6,  7,  8,  8,  8,  8,  8,  8,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  6,  9, 11, 11, 11, 12, 12, 12, 12, 12, 12,
+    12, 12, 12, 12
+  },
+  {
+    10,  3,  2,  2,  3,  4,  4,  5,  6,  6,  7,  7,  7,  8,  8,  9, 10, 10, 10, 11,
+    11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+    12, 12, 12, 12, 10, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 11, 11, 11, 12, 12, 12, 12, 12, 12,
+    12, 12, 12, 12
+  }
+};
+
+static const uint8_t ccitt_group3_2d_bits[11] = {
+    1, 1, 2, 2, 2, 1, 3, 3, 3, 1, 1
+};
+
+static const uint8_t ccitt_group3_2d_lens[11] = {
+    4, 3, 7, 6, 3, 1, 3, 6, 7, 7, 9
+};
+
+static VLC ccitt_vlc[2], ccitt_group3_2d_vlc;
+
+av_cold void ff_ccitt_unpack_init()
+{
+    static VLC_TYPE code_table1[528][2];
+    static VLC_TYPE code_table2[648][2];
+    int i;
+    static int initialized = 0;
+
+    if(initialized)
+        return;
+    ccitt_vlc[0].table = code_table1;
+    ccitt_vlc[0].table_allocated = 528;
+    ccitt_vlc[1].table = code_table2;
+    ccitt_vlc[1].table_allocated = 648;
+    for(i = 0; i < 2; i++){
+        init_vlc_sparse(&ccitt_vlc[i], 9, CCITT_SYMS,
+                        ccitt_codes_lens[i], 1, 1,
+                        ccitt_codes_bits[i], 1, 1, 
+                        ccitt_syms, 2, 2,
+                        INIT_VLC_USE_NEW_STATIC);
+    }
+    INIT_VLC_STATIC(&ccitt_group3_2d_vlc, 9, 11,
+                    ccitt_group3_2d_lens, 1, 1,
+                    ccitt_group3_2d_bits, 1, 1, 512);
+    initialized = 1;
+}
+
+
+static int decode_group3_1d_line(AVCodecContext *avctx, GetBitContext *gb,
+                                 int pix_left, int *runs)
+{
+    int mode = 0, run = 0;
+    unsigned int t;
+    for(;;){
+        t = get_vlc2(gb, ccitt_vlc[mode].table, 9, 2);
+        run += t;
+        if(t < 64){
+            pix_left -= run;
+            *runs++ = run;
+            if(!pix_left){
+                break;
+            }else if(pix_left < 0){
+                runs[-1] = 0;
+                av_log(avctx, AV_LOG_ERROR, "Run went out of bounds\n");
+                return -1;
+            }
+            run = 0;
+            mode = !mode;
+        }else if((int)t == -1){
+            av_log(avctx, AV_LOG_ERROR, "Incorrect code\n");
+            return -1;
+        }
+    }
+    *runs++ = 0;
+    return 0;
+}
+
+static int decode_group3_2d_line(AVCodecContext *avctx, GetBitContext *gb,
+                                 int pix_left, int *runs, const int *ref)
+{
+    int mode = 0, offs = 0, run = 0, saved_run = 0, t;
+    int run_off = 0;
+
+    while(pix_left > 0){
+        int cmode = get_vlc2(gb, ccitt_group3_2d_vlc.table, 9, 1);
+        //sync line pointers
+        while(run_off <= offs && run_off < avctx->width){
+            run_off += *ref++;
+            run_off += *ref++;
+        }
+        if(cmode == -1){
+            av_log(avctx, AV_LOG_ERROR, "Incorrect mode VLC\n");
+            return -1;
+        }
+        if(!cmode){//pass mode
+            run_off += *ref++;
+            run = run_off - offs;
+            run_off += *ref++;
+            pix_left -= run;
+            offs += run;
+            saved_run += run;
+        }else if(cmode == 1){//horizontal mode
+            int k;
+            for(k = 0; k < 2; k++){
+                run = 0;
+                for(;;){
+                    t = get_vlc2(gb, ccitt_vlc[mode].table, 9, 2);
+                    if(t == -1){
+                        av_log(avctx, AV_LOG_ERROR, "Incorrect code\n");
+                        return -1;
+                    }
+                    run += t;
+                    if(t < 64)
+                        break;
+                }
+                *runs++ = run + saved_run;
+                saved_run = 0;
+                if(pix_left < run){
+                    av_log(avctx, AV_LOG_ERROR, "Run went out of bounds\n");
+                    return -1;
+                }
+                pix_left -= run;
+                offs += run;
+                mode = !mode;
+            }
+        }else if(cmode == 9 || cmode == 10){
+            av_log(avctx, AV_LOG_ERROR, "Special modes are not supported (yet)\n");
+            return -1;
+        }else{//vertical mode
+            run = run_off - offs + (cmode - 5);
+            if(cmode >= 5)
+                run_off += *ref++;
+            else
+                run_off -= *--ref;
+            pix_left -= run;
+            offs += run;
+            *runs++ = run + saved_run;
+            saved_run = 0;
+            mode = !mode;
+        }
+    }
+    *runs++ = 0;
+    return 0;
+}
+
+static void put_line(uint8_t *dst, int size, int width, const int *runs)
+{
+    PutBitContext pb;
+    int run, mode = 0, pix_left = width, run_idx = 0;
+
+    init_put_bits(&pb, dst, size*8);
+    if(!runs[0]){
+        run_idx++;
+        mode = !mode;
+    }
+    while(pix_left > 0){
+        run = runs[run_idx++];
+        pix_left -= run;
+        for(; run > 16; run -= 16)
+            put_sbits(&pb, 16, -mode);
+        put_sbits(&pb, run, -mode);
+        mode = !mode;
+    }
+}
+
+static int find_group3_syncmarker(GetBitContext *gb, int srcsize)
+{
+    int state = get_bits(gb, 12);
+    int rem = srcsize - get_bits_count(gb);
+    while((state & 0xFFF) != 1){
+        state = (state << 1) | get_bits1(gb);
+        if(--rem <= 0)
+            return -1;
+    }
+    return 0;
+}
+
+int ff_ccitt_unpack_1d(AVCodecContext *avctx,
+                       const uint8_t *src, int srcsize,
+                       uint8_t *dst, int height, int stride)
+{
+    int j;
+    GetBitContext gb;
+    int *runs, *last;
+
+    runs = av_malloc(avctx->width * sizeof(runs[0]));
+    last = av_malloc(avctx->width * sizeof(last[0]));
+    init_get_bits(&gb, src, srcsize*8);
+    for(j = 0; j < height; j++){
+        if(find_group3_syncmarker(&gb, srcsize*8) < 0)
+            break;
+        if(decode_group3_1d_line(avctx, &gb, avctx->width, runs) < 0){
+            put_line(dst, stride, avctx->width, last);
+        }else{
+            put_line(dst, stride, avctx->width, runs);
+            FFSWAP(int*, last, runs);
+        }
+        dst += stride;
+    }
+    av_free(runs);
+    av_free(last);
+    return 0;
+}
+
+int ff_ccitt_unpack_2d(AVCodecContext *avctx,
+                       const uint8_t *src, int srcsize,
+                       uint8_t *dst, int height, int stride, int g4)
+{
+    int j;
+    GetBitContext gb;
+    int *runs, *ref;
+    int ret;
+
+    runs = av_malloc((avctx->width + 1) * sizeof(runs[0]));
+    ref  = av_malloc((avctx->width + 1) * sizeof(ref[0]));
+    runs[0] = 0;
+    ref[0] = 0;
+    ref[1] = avctx->width;
+    init_get_bits(&gb, src, srcsize*8);
+    for(j = 0; j < height; j++){
+        if(g4){
+            ret = decode_group3_2d_line(avctx, &gb, avctx->width, runs + 1, ref);
+            if(ret < 0){
+                av_free(runs);
+                av_free(ref);
+                return -1;
+            }
+        }else{
+            if(find_group3_syncmarker(&gb, srcsize*8) < 0)
+                break;
+            if(get_bits1(&gb))
+                ret = decode_group3_1d_line(avctx, &gb, avctx->width, runs + 1);
+            else
+                ret = decode_group3_2d_line(avctx, &gb, avctx->width, runs + 1, ref);
+        }
+        if(ret < 0){
+            put_line(dst, stride, avctx->width, ref + 1);
+        }else{
+            put_line(dst, stride, avctx->width, runs + 1);
+            FFSWAP(int*, runs, ref);
+        }
+        dst += stride;
+    }
+    av_free(runs);
+    av_free(ref);
+    return 0;
+}



More information about the ffmpeg-devel mailing list