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

Kostya kostya.shishkov
Wed Dec 24 07:06:13 CET 2008


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.
[...]
> > > 
> > > how is this supposed to work?
> > > once a line is damaged and lost there can be 1 line less thus this can
> > > still run out of data and fail.
> > 
> > it's the question of what to do with damaged data 
> 
> what do you prefer, no image or a image with a missing line?
> or did i misunderstand you?
 
we have three cases here:
1. group 3 1-d only - we have syncmarkers and each line is decoded independently
2. group 3 2-d - we have lines coded independently followed by K lines coded
    depending on the previous line
3. group 4 - all lines are coded depending on previous ones

so, in first two cases we can show broken image, in the third one it's better
to give up (which current code does now)
 
> [...]
> > @@ -103,6 +105,29 @@
> >              return -1;
> >          }
> >      }
> > +    if(s->compr == TIFF_CCITT_RLE || s->compr == TIFF_G3 || s->compr == TIFF_G4){
> > +        int i, ret = 0;
> 
> > +        uint8_t *src2;
> > +
> > +        src2 = av_malloc(size);
> 
> can be merged

merged 
 
> [...]
> > +static int decode_group3_1d_line(AVCodecContext *avctx, GetBitContext *gb,
> > +                                 int pix_left, int *runs)
> > +{
> > +    int mode = 0, run = 0, t;
> > +    while(pix_left){
> > +        t = get_vlc2(gb, ccitt_vlc[mode].table, 9, 2);
> > +        run += t;
> > +        if(t == -1){
> > +            av_log(avctx, AV_LOG_ERROR, "Incorrect code\n");
> > +            return -1;
> > +        }
> > +        if(t >= 64)
> > +            continue;
> > +        pix_left -= run;
> > +        if(pix_left < 0){
> > +            av_log(avctx, AV_LOG_ERROR, "Run went out of bounds\n");
> > +            return -1;
> > +        }
> > +        *runs++ = run;
> > +        run = 0;
> > +        mode = !mode;
> > +    }
> > +    *runs++ = 0;
> > +    return 0;
> > +}
> 
> still way more checks than neeeded

changed 
 
> [...]
> > +static void put_line(uint8_t *dst, int size, int width, const int *runs)
> > +{
> > +    PutBitContext pb;
> > +    int run, mode = 0, pix_left = width;
> > +
> > +    init_put_bits(&pb, dst, size*8);
> > +    while(pix_left > 0){
> > +        run = *runs++;
> > +        pix_left -= run;
> 
> > +        for(; run >= 16; run -= 16)
> > +            put_sbits(&pb, 16, -mode);
> > +        if(run)
> > +            put_sbits(&pb, run, -mode);
> 
> for(; run > 16; run -= 16)
>     put_sbits(&pb, 16, -mode);
> put_sbits(&pb, run, -mode);
 
done 
 
> > +        mode = !mode;
> > +    }
> > +}
> > +
> > +static int find_group3_syncmarker(GetBitContext *gb, int srcsize)
> > +{
> > +    int ret = 0;
> > +    while(show_bits(gb, 12) != 1){
> > +        skip_bits1(gb);
> > +        ret = 1;
> > +        if(get_bits_count(gb) >= srcsize)
> > +            return -1;
> > +    }
> > +    skip_bits(gb, 12);
> > +    return ret;
> > +}
> 
> int rem= srcsize - get_bits_count(gb);
> uint32_t state=-1;
> while(rem-- > 0){
>     state+= state + get_bits1();
>     if((state&0xFFF) == 1)
>         return 1;
> }
> return 0;

implemented in similar way 
 
> [...]
> > +int ff_ccitt_unpack_group3_2d(AVCodecContext *avctx,
> > +                              const uint8_t *src, int srcsize,
> > +                              uint8_t *dst, int height, int stride)
> > +{
> > +    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(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){
> > +            av_free(runs);
> > +            av_free(ref);
> > +            return -1;
> > +        }
> > +        put_line(dst, stride, avctx->width, runs + 1);
> > +        FFSWAP(int*, runs, ref);
> > +        dst += stride;
> > +    }
> > +    av_free(runs);
> > +    av_free(ref);
> > +    return 0;
> > +}
> > +
> > +int ff_ccitt_unpack_group4(AVCodecContext *avctx,
> > +                           const uint8_t *src, int srcsize,
> > +                           uint8_t *dst, int height, int stride)
> > +{
> > +    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++){
> > +        ret = decode_group3_2d_line(avctx, &gb, avctx->width, runs + 1, ref);
> > +        if(ret < 0){
> > +            av_free(runs);
> > +            av_free(ref);
> > +            return -1;
> > +        }
> > +        put_line(dst, stride, avctx->width, runs + 1);
> > +        FFSWAP(int*, runs, ref);
> > +        dst += stride;
> > +    }
> > +    av_free(runs);
> > +    av_free(ref);
> > +    return 0;
> > +}
> 
> this function looks duplicated

factorized 
 
> [...]
> -- 
> 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,28 @@
             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_group3_1d(s->avctx, src2, size, dst, lines, stride);
+            break;
+        case TIFF_G3:
+            ret = ff_ccitt_unpack_group3_2d(s->avctx, src2, size, dst, lines, stride);
+            break;
+        case TIFF_G4:
+            ret = ff_ccitt_unpack_group4   (s->avctx, src2, size, dst, lines, stride);
+            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 +289,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 +303,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 +393,10 @@
             return -1;
         }
         break;
+    case TIFF_T4OPTIONS:
+    case TIFF_T6OPTIONS:
+        s->fax_opts = value;
+        break;
     }
     return 0;
 }
@@ -487,6 +511,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,58 @@
+/*
+ * 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_group3_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 method
+ */
+int ff_ccitt_unpack_group3_2d(AVCodecContext *avctx,
+                              const uint8_t *src, int srcsize,
+                              uint8_t *dst, int height, int stride);
+
+/**
+ * unpack data compressed with CCITT Group 4 1-D method
+ */
+int ff_ccitt_unpack_group4(AVCodecContext *avctx,
+                           const uint8_t *src, int srcsize,
+                           uint8_t *dst, int height, int stride);
+
+#endif /* AVCODEC_FAXCOMPR_H */
Index: libavcodec/faxcompr.c
===================================================================
--- libavcodec/faxcompr.c	(revision 0)
+++ libavcodec/faxcompr.c	(revision 0)
@@ -0,0 +1,330 @@
+/*
+ * 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;
+    while(pix_left){
+        t = get_vlc2(gb, ccitt_vlc[mode].table, 9, 2);
+        run += t;
+        if(t < 64){
+            pix_left -= run;
+            if(pix_left < 0){
+                av_log(avctx, AV_LOG_ERROR, "Run went out of bounds\n");
+                return -1;
+            }
+            *runs++ = run;
+            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++];
+        if(!run || run_idx >= width)
+            return;
+        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_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;
+    }
+    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;
+        }
+        put_line(dst, stride, avctx->width, runs + 1);
+        FFSWAP(int*, runs, ref);
+        dst += stride;
+    }
+    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);
+}



More information about the ffmpeg-devel mailing list