[Ffmpeg-devel] [PATCH] simple internal lzo decoder

Reimar Döffinger Reimar.Doeffinger
Tue Jan 10 22:07:28 CET 2006


Hi,
the attached patch adds a simple and probably slow LZO decoder to ffmpeg and
makes the CamStudio decoder use it. For simplicity it also disables support
for external liblzo if that is wanted (though currently the external
decoder would be the default with --enable-gpl, which I think is not a
good idea).
Please comment (and of course, test it as well).
Btw. since I could not find any specs, I created this decompressor by
"converting" the original code in a drawing and reimplementing from
there (after some "graph-optimizations"). The first time I tried it like
this, I guess I really should put up a picture of the drawing when I get the
time :-)

Greetings,
Reimar D?ffinger
-------------- next part --------------
Index: libavcodec/Makefile
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/Makefile,v
retrieving revision 1.219
diff -u -r1.219 Makefile
--- libavcodec/Makefile	9 Jan 2006 15:41:39 -0000	1.219
+++ libavcodec/Makefile	10 Jan 2006 20:47:31 -0000
@@ -18,7 +18,7 @@
       fft.o mdct.o raw.o golomb.o cabac.o\
       dpcm.o adx.o faandct.o parser.o g726.o \
       vp3dsp.o h264idct.o rangecoder.o pnm.o h263.o msmpeg4.o h263dec.o \
-      opt.o
+      opt.o lzo.o
 
 ifeq ($(CONFIG_AASC_DECODER),yes)
     OBJS+= aasc.o
Index: libavcodec/cscd.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/cscd.c,v
retrieving revision 1.1
diff -u -r1.1 cscd.c
--- libavcodec/cscd.c	9 Jan 2006 15:41:39 -0000	1.1
+++ libavcodec/cscd.c	10 Jan 2006 20:47:33 -0000
@@ -25,9 +25,7 @@
 #ifdef CONFIG_ZLIB
 #include <zlib.h>
 #endif
-#ifdef CONFIG_LZO
-#include <lzo1x.h>
-#endif
+#include "lzo.h"
 
 typedef struct {
     AVFrame pic;
@@ -158,16 +156,11 @@
     // decompress data
     switch ((buf[0] >> 1) & 7) {
         case 0: { // lzo compression
-#ifdef CONFIG_LZO
-            unsigned int dlen = c->decomp_size;
-            if (lzo1x_decompress_safe(&buf[2], buf_size - 2,
-                       c->decomp_buf, &dlen, NULL) != LZO_E_OK)
+            int outlen = c->decomp_size, inlen = buf_size - 2;
+            if (lzo1x_decode(c->decomp_buf, &outlen,
+                       &buf[2], &inlen) != LZO_FINISHED)
                 av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
             break;
-#else
-            av_log(avctx, AV_LOG_ERROR, "compiled without lzo (GPL) support\n");
-            return -1;
-#endif
         }
         case 1: { // zlib compression
 #ifdef CONFIG_ZLIB
Index: libavcodec/lzo.c
===================================================================
RCS file: libavcodec/lzo.c
diff -N libavcodec/lzo.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libavcodec/lzo.c	10 Jan 2006 20:47:33 -0000
@@ -0,0 +1,181 @@
+/*
+ * LZO 1x decompression
+ * Copyright (c) 2006 Reimar Doeffinger
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "common.h"
+#include "lzo.h"
+
+typedef struct LZOContext {
+    uint8_t *in;
+    int in_remain;
+    uint8_t *out;
+    int out_remain, out_size;
+    int error;
+} LZOContext;
+
+/**
+ * \brief read one byte from input buffer, avoiding overrun
+ * \return byte read
+ */
+static inline int get_byte(LZOContext *c) {
+    int res = c->in[0];
+    if (c->in_remain) {
+      c->in++;
+      c->in_remain--;
+    } else
+      c->error |= LZO_INPUT_DEPLETED;
+    return res;
+}
+
+/**
+ * \brief decode a length value in the coding used by lzo
+ * \param x previous byte value
+ * \param mask bits used from x
+ * \return decoded length value
+ */
+static inline int get_len(LZOContext *c, int x, int mask) {
+    int cnt = x & mask;
+    if (!cnt) {
+        while (!(x = get_byte(c))) cnt += 255;
+        cnt += mask + x;
+    }
+    return cnt;
+}
+
+/**
+ * \brief copy bytes from input to output buffer with checking
+ * \param cnt number of bytes to copy, must be > 0
+ */
+static inline void copy(LZOContext *c, int cnt) {
+    if (cnt > c->in_remain) {
+        cnt = c->in_remain;
+        c->error |= LZO_INPUT_DEPLETED;
+    }
+    if (cnt > c->out_remain) {
+        cnt = c->out_remain;
+        c->error |= LZO_OUTPUT_FULL;
+    }
+    memcpy(c->out, c->in, cnt);
+    c->in_remain -= cnt;
+    c->out_remain -= cnt;
+    do {
+        *c->out++ = *c->in++;
+    } while (--cnt);
+}
+
+/**
+ * \brief copy previously decoded bytes to current position
+ * \param back how many bytes back we start
+ * \param cnt number of bytes to copy, must be > 0
+ *
+ * cnt > back is valid, this will copy the bytes we just copied.
+ */
+static inline void copy_backptr(LZOContext *c, int back, int cnt) {
+    if (back > c->out_size - c->out_remain) {
+        c->error |= LZO_INVALID_BACKPTR;
+        return;
+    }
+    if (cnt > c->out_remain) {
+        cnt = c->out_remain;
+        c->error |= LZO_OUTPUT_FULL;
+    }
+    c->out_remain -= cnt;
+    do {
+        *c->out++ = c->out[-back];
+    } while (--cnt);
+}
+
+/**
+ * \brief decode LZO 1x compressed data
+ * \param out output buffer
+ * \param outlen size of output buffer, number of bytes left are returned here
+ * \param in input buffer
+ * \param inlen size of input buffer, number of bytes left are returned here
+ * \return error flags, see lzo.h
+ */
+int lzo1x_decode(void *out, int *outlen, void *in, int *inlen) {
+    enum {COPY, BACKPTR} state = COPY;
+    int x;
+    LZOContext c;
+    c.in = in;
+    c.in_remain = *inlen;
+    c.out = out;
+    c.out_size = c.out_remain = *outlen;
+    c.error = 0;
+    x = get_byte(&c);
+    if (x > 17) {
+        copy(&c, x - 17);
+        x = get_byte(&c);
+        if (x < 16) c.error |= LZO_ERROR;
+    }
+    while (!c.error) {
+        int cnt, back, back_cnt;
+        switch (state) {
+            case COPY:
+                if (x >= 16) {
+                    state = BACKPTR;
+                    continue;
+                }
+                cnt = get_len(&c, x, 15);
+                copy(&c, cnt + 3);
+                x = get_byte(&c);
+                if (x >= 16) {
+                    state = BACKPTR;
+                    continue;
+                }
+                cnt = x & 3;
+                back = (1 << 11) + (x >> 2) + (get_byte(&c) << 2) + 1;
+                back_cnt = 3;
+                break;
+            case BACKPTR:
+                if (x >> 6) {
+                    back_cnt = (x >> 5) - 1;
+                    back = 1 + ((x >> 2) & 7) + (get_byte(&c) << 3);
+                } else if (x >> 5) {
+                    back_cnt = get_len(&c, x, 31);
+                    x = get_byte(&c);
+                    back = 1 + (x >> 2) + (get_byte(&c) << 6);
+                } else if (x >> 4) {
+                    back_cnt = get_len(&c, x, 7);
+                    back = (1 << 14) + ((x & 8) << 11);
+                    x = get_byte(&c);
+                    back += (x >> 2) + (get_byte(&c) << 6);
+                    if (back == (1 << 14)) {
+                      c.error |= LZO_FINISHED;
+                      if (back_cnt != 1)
+                        c.error |= LZO_ERROR;
+                      continue;
+                    }
+                } else {
+                    back_cnt = 0;
+                    back = 1 + (x >> 2) + (get_byte(&c) << 2);
+                }
+                back_cnt += 2;
+                cnt = x & 3;
+                break;
+        }
+        copy_backptr(&c, back, back_cnt);
+        if (cnt)
+            copy(&c, cnt);
+        else
+            state = (state == COPY) ? BACKPTR : COPY;
+        x = get_byte(&c);
+    }
+    *inlen = c.in_remain;
+    *outlen = c.out_remain;
+    return c.error;
+}
Index: libavcodec/lzo.h
===================================================================
RCS file: libavcodec/lzo.h
diff -N libavcodec/lzo.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libavcodec/lzo.h	10 Jan 2006 20:47:33 -0000
@@ -0,0 +1,12 @@
+#ifndef _LZO_H
+#define LZO_H
+
+#define LZO_INPUT_DEPLETED 1
+#define LZO_OUTPUT_FULL 2
+#define LZO_INVALID_BACKPTR 4
+#define LZO_ERROR 8
+#define LZO_FINISHED 16
+
+int lzo1x_decode(void *out, int *outlen, void *in, int *inlen);
+
+#endif



More information about the ffmpeg-devel mailing list