[FFmpeg-devel] [PATCH] Common M$-RLE decoding code

Kostya kostya.shishkov
Wed Sep 17 14:56:37 CEST 2008


On Wed, Sep 17, 2008 at 01:32:21PM +0200, Michael Niedermayer wrote:
> On Wed, Sep 17, 2008 at 12:14:38PM +0300, Kostya wrote:
> > Here's the think Mike should have done long ago.
> > I've taken his decoder for 4-bpp RLE and mine for >= 8bpp RLE
> > and reused it in AASC, MS RLE video, TSCC and experimental RLE decoding
> > support in BMP (along with 8bpp support).
> > Tested on different samples from MPHQ, seems to work fine on all of them
> > except suzie_appl_rle[48].avi where it hasn't worked before too.
> 
> I think the factorization of code and the addition of new code should
> be in seperate patches.
 
Here's just factorization.
 
> [...]
> -- 
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
-------------- next part --------------
Index: libavcodec/Makefile
===================================================================
--- libavcodec/Makefile	(revision 15342)
+++ libavcodec/Makefile	(working copy)
@@ -26,7 +26,7 @@
 OBJS-$(CONFIG_ENCODERS)                += faandct.o jfdctfst.o jfdctint.o
 
 OBJS-$(CONFIG_AAC_DECODER)             += aac.o aactab.o mdct.o fft.o
-OBJS-$(CONFIG_AASC_DECODER)            += aasc.o
+OBJS-$(CONFIG_AASC_DECODER)            += aasc.o msrledec.o
 OBJS-$(CONFIG_AC3_DECODER)             += eac3dec.o ac3dec.o ac3tab.o ac3dec_data.o ac3.o mdct.o fft.o
 OBJS-$(CONFIG_AC3_ENCODER)             += ac3enc.o ac3tab.o ac3.o
 OBJS-$(CONFIG_ALAC_DECODER)            += alac.o
@@ -136,7 +136,7 @@
 OBJS-$(CONFIG_MSMPEG4V2_ENCODER)       += msmpeg4.o msmpeg4data.o mpegvideo_enc.o motion_est.o ratecontrol.o h263.o mpeg12data.o mpegvideo.o error_resilience.o
 OBJS-$(CONFIG_MSMPEG4V3_DECODER)       += msmpeg4.o msmpeg4data.o h263dec.o h263.o mpeg12data.o mpegvideo.o error_resilience.o
 OBJS-$(CONFIG_MSMPEG4V3_ENCODER)       += msmpeg4.o msmpeg4data.o mpegvideo_enc.o motion_est.o ratecontrol.o h263.o mpeg12data.o mpegvideo.o error_resilience.o
-OBJS-$(CONFIG_MSRLE_DECODER)           += msrle.o
+OBJS-$(CONFIG_MSRLE_DECODER)           += msrle.o msrledec.o
 OBJS-$(CONFIG_MSVIDEO1_DECODER)        += msvideo1.o
 OBJS-$(CONFIG_MSZH_DECODER)            += lcldec.o
 OBJS-$(CONFIG_NELLYMOSER_DECODER)      += nellymoserdec.o nellymoser.o mdct.o fft.o
@@ -197,7 +197,7 @@
 OBJS-$(CONFIG_TRUEMOTION1_DECODER)     += truemotion1.o
 OBJS-$(CONFIG_TRUEMOTION2_DECODER)     += truemotion2.o
 OBJS-$(CONFIG_TRUESPEECH_DECODER)      += truespeech.o
-OBJS-$(CONFIG_TSCC_DECODER)            += tscc.o
+OBJS-$(CONFIG_TSCC_DECODER)            += tscc.o msrledec.o
 OBJS-$(CONFIG_TTA_DECODER)             += tta.o
 OBJS-$(CONFIG_TXD_DECODER)             += txd.o s3tc.o
 OBJS-$(CONFIG_ULTI_DECODER)            += ulti.o
Index: libavcodec/msrle.c
===================================================================
--- libavcodec/msrle.c	(revision 15342)
+++ libavcodec/msrle.c	(working copy)
@@ -38,6 +38,7 @@
 
 #include "avcodec.h"
 #include "dsputil.h"
+#include "msrledec.h"
 
 typedef struct MsrleContext {
     AVCodecContext *avctx;
@@ -48,194 +49,6 @@
 
 } MsrleContext;
 
-#define FETCH_NEXT_STREAM_BYTE() \
-    if (stream_ptr >= s->size) \
-    { \
-      av_log(s->avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (1)\n"); \
-      return; \
-    } \
-    stream_byte = s->buf[stream_ptr++];
-
-static void msrle_decode_pal4(MsrleContext *s)
-{
-    int stream_ptr = 0;
-    unsigned char rle_code;
-    unsigned char extra_byte, odd_pixel;
-    unsigned char stream_byte;
-    int pixel_ptr = 0;
-    int row_dec = s->frame.linesize[0];
-    int row_ptr = (s->avctx->height - 1) * row_dec;
-    int frame_size = row_dec * s->avctx->height;
-    int i;
-
-    /* make the palette available */
-    memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
-    if (s->avctx->palctrl->palette_changed) {
-        s->frame.palette_has_changed = 1;
-        s->avctx->palctrl->palette_changed = 0;
-    }
-
-    while (row_ptr >= 0) {
-        FETCH_NEXT_STREAM_BYTE();
-        rle_code = stream_byte;
-        if (rle_code == 0) {
-            /* fetch the next byte to see how to handle escape code */
-            FETCH_NEXT_STREAM_BYTE();
-            if (stream_byte == 0) {
-                /* line is done, goto the next one */
-                row_ptr -= row_dec;
-                pixel_ptr = 0;
-            } else if (stream_byte == 1) {
-                /* decode is done */
-                return;
-            } else if (stream_byte == 2) {
-                /* reposition frame decode coordinates */
-                FETCH_NEXT_STREAM_BYTE();
-                pixel_ptr += stream_byte;
-                FETCH_NEXT_STREAM_BYTE();
-                row_ptr -= stream_byte * row_dec;
-        } else {
-            // copy pixels from encoded stream
-            odd_pixel =  stream_byte & 1;
-            rle_code = (stream_byte + 1) / 2;
-            extra_byte = rle_code & 0x01;
-            if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
-                (row_ptr < 0)) {
-                av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
-                return;
-            }
-
-            for (i = 0; i < rle_code; i++) {
-                if (pixel_ptr >= s->avctx->width)
-                    break;
-                FETCH_NEXT_STREAM_BYTE();
-                s->frame.data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
-                pixel_ptr++;
-                if (i + 1 == rle_code && odd_pixel)
-                    break;
-                if (pixel_ptr >= s->avctx->width)
-                    break;
-                s->frame.data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
-                pixel_ptr++;
-            }
-
-            // if the RLE code is odd, skip a byte in the stream
-            if (extra_byte)
-              stream_ptr++;
-            }
-        } else {
-            // decode a run of data
-            if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
-                (row_ptr < 0)) {
-                av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
-                return;
-            }
-            FETCH_NEXT_STREAM_BYTE();
-            for (i = 0; i < rle_code; i++) {
-                if (pixel_ptr >= s->avctx->width)
-                    break;
-                if ((i & 1) == 0)
-                    s->frame.data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
-                else
-                    s->frame.data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
-                pixel_ptr++;
-            }
-        }
-    }
-
-    /* one last sanity check on the way out */
-    if (stream_ptr < s->size)
-        av_log(s->avctx, AV_LOG_ERROR, " MS RLE: ended frame decode with bytes left over (%d < %d)\n",
-            stream_ptr, s->size);
-}
-
-
-
-static void msrle_decode_pal8(MsrleContext *s)
-{
-    int stream_ptr = 0;
-    unsigned char rle_code;
-    unsigned char extra_byte;
-    unsigned char stream_byte;
-    int pixel_ptr = 0;
-    int row_dec = s->frame.linesize[0];
-    int row_ptr = (s->avctx->height - 1) * row_dec;
-    int frame_size = row_dec * s->avctx->height;
-
-    /* make the palette available */
-    memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
-    if (s->avctx->palctrl->palette_changed) {
-        s->frame.palette_has_changed = 1;
-        s->avctx->palctrl->palette_changed = 0;
-    }
-
-    while (row_ptr >= 0) {
-        FETCH_NEXT_STREAM_BYTE();
-        rle_code = stream_byte;
-        if (rle_code == 0) {
-            /* fetch the next byte to see how to handle escape code */
-            FETCH_NEXT_STREAM_BYTE();
-            if (stream_byte == 0) {
-                /* line is done, goto the next one */
-                row_ptr -= row_dec;
-                pixel_ptr = 0;
-            } else if (stream_byte == 1) {
-                /* decode is done */
-                return;
-            } else if (stream_byte == 2) {
-                /* reposition frame decode coordinates */
-                FETCH_NEXT_STREAM_BYTE();
-                pixel_ptr += stream_byte;
-                FETCH_NEXT_STREAM_BYTE();
-                row_ptr -= stream_byte * row_dec;
-            } else {
-                /* copy pixels from encoded stream */
-                if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
-                    (row_ptr < 0)) {
-                    av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
-                    return;
-                }
-
-                rle_code = stream_byte;
-                extra_byte = stream_byte & 0x01;
-                if (stream_ptr + rle_code + extra_byte > s->size) {
-                    av_log(s->avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (2)\n");
-                    return;
-                }
-
-                while (rle_code--) {
-                    FETCH_NEXT_STREAM_BYTE();
-                    s->frame.data[0][row_ptr + pixel_ptr] = stream_byte;
-                    pixel_ptr++;
-                }
-
-                /* if the RLE code is odd, skip a byte in the stream */
-                if (extra_byte)
-                    stream_ptr++;
-            }
-        } else {
-            /* decode a run of data */
-            if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
-                (row_ptr < 0)) {
-                av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (2)\n");
-                return;
-            }
-
-            FETCH_NEXT_STREAM_BYTE();
-
-            while(rle_code--) {
-                s->frame.data[0][row_ptr + pixel_ptr] = stream_byte;
-                pixel_ptr++;
-            }
-        }
-    }
-
-    /* one last sanity check on the way out */
-    if (stream_ptr < s->size)
-        av_log(s->avctx, AV_LOG_ERROR, " MS RLE: ended frame decode with bytes left over (%d < %d)\n",
-            stream_ptr, s->size);
-}
-
 static av_cold int msrle_decode_init(AVCodecContext *avctx)
 {
     MsrleContext *s = avctx->priv_data;
@@ -264,18 +77,15 @@
         return -1;
     }
 
-    switch (avctx->bits_per_coded_sample) {
-        case 8:
-            msrle_decode_pal8(s);
-            break;
-        case 4:
-            msrle_decode_pal4(s);
-            break;
-        default:
-            av_log(avctx, AV_LOG_ERROR, "Don't know how to decode depth %u.\n",
-                   avctx->bits_per_coded_sample);
+    /* make the palette available */
+    memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
+    if (s->avctx->palctrl->palette_changed) {
+        s->frame.palette_has_changed = 1;
+        s->avctx->palctrl->palette_changed = 0;
     }
 
+    ff_msrle_decode(avctx, &s->frame, avctx->bits_per_coded_sample, buf, buf_size);
+
     *data_size = sizeof(AVFrame);
     *(AVFrame*)data = s->frame;
 
Index: libavcodec/aasc.c
===================================================================
--- libavcodec/aasc.c	(revision 15342)
+++ libavcodec/aasc.c	(working copy)
@@ -30,6 +30,7 @@
 
 #include "avcodec.h"
 #include "dsputil.h"
+#include "msrledec.h"
 
 typedef struct AascContext {
     AVCodecContext *avctx;
@@ -61,13 +62,6 @@
                               const uint8_t *buf, int buf_size)
 {
     AascContext *s = avctx->priv_data;
-    int stream_ptr = 4;
-    unsigned char rle_code;
-    unsigned char stream_byte;
-    int pixel_ptr = 0;
-    int row_dec, row_ptr;
-    int frame_size;
-    int i;
 
     s->frame.reference = 1;
     s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
@@ -76,73 +70,8 @@
         return -1;
     }
 
-    row_dec = s->frame.linesize[0];
-    row_ptr = (s->avctx->height - 1) * row_dec;
-    frame_size = row_dec * s->avctx->height;
+    ff_msrle_decode(avctx, &s->frame, 8, buf, buf_size);
 
-    while (row_ptr >= 0) {
-        FETCH_NEXT_STREAM_BYTE();
-        rle_code = stream_byte;
-        if (rle_code == 0) {
-            /* fetch the next byte to see how to handle escape code */
-            FETCH_NEXT_STREAM_BYTE();
-            if (stream_byte == 0) {
-                /* line is done, goto the next one */
-                row_ptr -= row_dec;
-                pixel_ptr = 0;
-            } else if (stream_byte == 1) {
-                /* decode is done */
-                break;
-            } else if (stream_byte == 2) {
-                /* reposition frame decode coordinates */
-                FETCH_NEXT_STREAM_BYTE();
-                pixel_ptr += stream_byte;
-                FETCH_NEXT_STREAM_BYTE();
-                row_ptr -= stream_byte * row_dec;
-            } else {
-                /* copy pixels from encoded stream */
-                if ((pixel_ptr + stream_byte > avctx->width * 3) ||
-                    (row_ptr < 0)) {
-                    av_log(s->avctx, AV_LOG_ERROR, " AASC: frame ptr just went out of bounds (copy1)\n");
-                    break;
-                }
-
-                rle_code = stream_byte;
-                if (stream_ptr + rle_code > buf_size) {
-                    av_log(s->avctx, AV_LOG_ERROR, " AASC: stream ptr just went out of bounds (copy2)\n");
-                    break;
-                }
-
-                for (i = 0; i < rle_code; i++) {
-                    FETCH_NEXT_STREAM_BYTE();
-                    s->frame.data[0][row_ptr + pixel_ptr] = stream_byte;
-                    pixel_ptr++;
-                }
-                if (rle_code & 1)
-                    stream_ptr++;
-            }
-        } else {
-            /* decode a run of data */
-            if ((pixel_ptr + rle_code > avctx->width * 3) ||
-                (row_ptr < 0)) {
-                av_log(s->avctx, AV_LOG_ERROR, " AASC: frame ptr just went out of bounds (run1)\n");
-                break;
-            }
-
-            FETCH_NEXT_STREAM_BYTE();
-
-            while(rle_code--) {
-                s->frame.data[0][row_ptr + pixel_ptr] = stream_byte;
-                pixel_ptr++;
-            }
-        }
-    }
-
-    /* one last sanity check on the way out */
-    if (stream_ptr < buf_size)
-        av_log(s->avctx, AV_LOG_ERROR, " AASC: ended frame decode with bytes left over (%d < %d)\n",
-            stream_ptr, buf_size);
-
     *data_size = sizeof(AVFrame);
     *(AVFrame*)data = s->frame;
 
Index: libavcodec/msrledec.c
===================================================================
--- libavcodec/msrledec.c	(revision 0)
+++ libavcodec/msrledec.c	(revision 0)
@@ -0,0 +1,254 @@
+/*
+ * Micrsoft RLE Decoder
+ * 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
+ */
+
+/**
+ * @file msrledec.c
+ * MS RLE Decoder based on decoder by Mike Melanson
+ * For more information about the MS RLE format, visit:
+ *   http://www.multimedia.cx/msrle.txt
+ */
+
+#include "avcodec.h"
+
+#define FETCH_NEXT_STREAM_BYTE() \
+    if (stream_ptr >= data_size) \
+    { \
+      av_log(avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (1)\n"); \
+      return -1; \
+    } \
+    stream_byte = data[stream_ptr++];
+
+static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic,
+                              const uint8_t *data, int data_size)
+{
+    int stream_ptr = 0;
+    unsigned char rle_code;
+    unsigned char extra_byte, odd_pixel;
+    unsigned char stream_byte;
+    int pixel_ptr = 0;
+    int row_dec = pic->linesize[0];
+    int row_ptr = (avctx->height - 1) * row_dec;
+    int frame_size = row_dec * avctx->height;
+    int i;
+
+    while (row_ptr >= 0) {
+        FETCH_NEXT_STREAM_BYTE();
+        rle_code = stream_byte;
+        if (rle_code == 0) {
+            /* fetch the next byte to see how to handle escape code */
+            FETCH_NEXT_STREAM_BYTE();
+            if (stream_byte == 0) {
+                /* line is done, goto the next one */
+                row_ptr -= row_dec;
+                pixel_ptr = 0;
+            } else if (stream_byte == 1) {
+                /* decode is done */
+                return 0;
+            } else if (stream_byte == 2) {
+                /* reposition frame decode coordinates */
+                FETCH_NEXT_STREAM_BYTE();
+                pixel_ptr += stream_byte;
+                FETCH_NEXT_STREAM_BYTE();
+                row_ptr -= stream_byte * row_dec;
+        } else {
+            // copy pixels from encoded stream
+            odd_pixel =  stream_byte & 1;
+            rle_code = (stream_byte + 1) / 2;
+            extra_byte = rle_code & 0x01;
+            if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
+                (row_ptr < 0)) {
+                av_log(avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
+                return -1;
+            }
+
+            for (i = 0; i < rle_code; i++) {
+                if (pixel_ptr >= avctx->width)
+                    break;
+                FETCH_NEXT_STREAM_BYTE();
+                pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
+                pixel_ptr++;
+                if (i + 1 == rle_code && odd_pixel)
+                    break;
+                if (pixel_ptr >= avctx->width)
+                    break;
+                pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
+                pixel_ptr++;
+            }
+
+            // if the RLE code is odd, skip a byte in the stream
+            if (extra_byte)
+              stream_ptr++;
+            }
+        } else {
+            // decode a run of data
+            if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
+                (row_ptr < 0)) {
+                av_log(avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
+                return -1;
+            }
+            FETCH_NEXT_STREAM_BYTE();
+            for (i = 0; i < rle_code; i++) {
+                if (pixel_ptr >= avctx->width)
+                    break;
+                if ((i & 1) == 0)
+                    pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
+                else
+                    pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
+                pixel_ptr++;
+            }
+        }
+    }
+
+    /* one last sanity check on the way out */
+    if (stream_ptr < data_size) {
+        av_log(avctx, AV_LOG_ERROR, " MS RLE: ended frame decode with bytes left over (%d < %d)\n",
+            stream_ptr, data_size);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVPicture *pic, int depth,
+                                    const uint8_t *data, int srcsize)
+{
+    uint8_t *output, *output_end;
+    const uint8_t* src = data;
+    int p1, p2, line=avctx->height, pos=0, i;
+    uint16_t pix16;
+    uint32_t pix32;
+
+    output = pic->data[0] + (avctx->height - 1) * pic->linesize[0];
+    output_end = pic->data[0] + (avctx->height) * pic->linesize[0];
+    while(src < data + srcsize) {
+        p1 = *src++;
+        if(p1 == 0) { //Escape code
+            p2 = *src++;
+            if(p2 == 0) { //End-of-line
+                output = pic->data[0] + (--line) * pic->linesize[0];
+                if (line < 0)
+                    return -1;
+                pos = 0;
+                continue;
+            } else if(p2 == 1) { //End-of-picture
+                return 0;
+            } else if(p2 == 2) { //Skip
+                p1 = *src++;
+                p2 = *src++;
+                line -= p2;
+                if (line < 0)
+                    return -1;
+                pos += p1;
+                output = pic->data[0] + line * pic->linesize[0] + pos * (depth >> 3);
+                continue;
+            }
+            // Copy data
+            if (output + p2 * (depth >> 3) > output_end) {
+                src += p2 * (depth >> 3);
+                continue;
+            }
+            if ((depth == 8) || (depth == 24)) {
+                for(i = 0; i < p2 * (depth >> 3); i++) {
+                    *output++ = *src++;
+                }
+                // RLE8 copy is actually padded - and runs are not!
+                if(depth == 8 && (p2 & 1)) {
+                    src++;
+                }
+            } else if (depth == 16) {
+                for(i = 0; i < p2; i++) {
+                    pix16 = AV_RL16(src);
+                    src += 2;
+                    *(uint16_t*)output = pix16;
+                    output += 2;
+                }
+            } else if (depth == 32) {
+                for(i = 0; i < p2; i++) {
+                    pix32 = AV_RL32(src);
+                    src += 4;
+                    *(uint32_t*)output = pix32;
+                    output += 4;
+                }
+            }
+            pos += p2;
+        } else { //Run of pixels
+            int pix[4]; //original pixel
+            switch(depth){
+            case  8: pix[0] = *src++;
+                     break;
+            case 16: pix16 = AV_RL16(src);
+                     src += 2;
+                     *(uint16_t*)pix = pix16;
+                     break;
+            case 24: pix[0] = *src++;
+                     pix[1] = *src++;
+                     pix[2] = *src++;
+                     break;
+            case 32: pix32 = AV_RL32(src);
+                     src += 4;
+                     *(uint32_t*)pix = pix32;
+                     break;
+            }
+            if (output + p1 * (depth >> 3) > output_end)
+                continue;
+            for(i = 0; i < p1; i++) {
+                switch(depth){
+                case  8: *output++ = pix[0];
+                         break;
+                case 16: *(uint16_t*)output = pix16;
+                         output += 2;
+                         break;
+                case 24: *output++ = pix[0];
+                         *output++ = pix[1];
+                         *output++ = pix[2];
+                         break;
+                case 32: *(uint32_t*)output = pix32;
+                         output += 4;
+                         break;
+                }
+            }
+            pos += p1;
+        }
+    }
+
+    av_log(avctx, AV_LOG_WARNING, "MS RLE warning: no End-of-picture code\n");
+    return 0;
+}
+
+
+int ff_msrle_decode(AVCodecContext *avctx, AVPicture *pic, int depth,
+                    const uint8_t* data, int data_size)
+{
+    switch(depth){
+    case  4:
+        return msrle_decode_pal4(avctx, pic, data, data_size);
+    case  8:
+    case 16:
+    case 24:
+    case 32:
+        return msrle_decode_8_16_24_32(avctx, pic, depth, data, data_size);
+    default:
+        av_log(avctx, AV_LOG_ERROR, "Unknown depth %d\n", depth);
+        return -1;
+    }
+}
+
Index: libavcodec/msrledec.h
===================================================================
--- libavcodec/msrledec.h	(revision 0)
+++ libavcodec/msrledec.h	(revision 0)
@@ -0,0 +1,40 @@
+/*
+ * Micrsoft RLE Decoder
+ * 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
+ */
+
+#ifndef AVCODEC_MSRLEDEC_H
+#define AVCODEC_MSRLEDEC_H
+
+#include "avcodec.h"
+
+/**
+ * decode stream in MS RLE format into frame
+ *
+ * @param avctx     codec context
+ * @param pic       destination frame
+ * @param depth     bit depth
+ * @param data      input stream
+ * @param data_size input size
+ */
+int ff_msrle_decode(AVCodecContext *avctx, AVPicture *pic, int depth,
+                    const uint8_t* data, int data_size);
+
+#endif /* AVCODEC_MSRLEDEC_H */
+
Index: libavcodec/tscc.c
===================================================================
--- libavcodec/tscc.c	(revision 15342)
+++ libavcodec/tscc.c	(working copy)
@@ -39,6 +39,7 @@
 #include <stdlib.h>
 
 #include "avcodec.h"
+#include "msrledec.h"
 
 #ifdef CONFIG_ZLIB
 #include <zlib.h>
@@ -67,118 +68,6 @@
 
 /*
  *
- * Decode RLE - almost identical to Windows BMP RLE8
- *              and enhanced to bigger color depths
- *
- */
-
-static int decode_rle(CamtasiaContext *c, unsigned int srcsize)
-{
-    unsigned char *src = c->decomp_buf;
-    unsigned char *output, *output_end;
-    int p1, p2, line=c->height, pos=0, i;
-    uint16_t pix16;
-    uint32_t pix32;
-
-    output = c->pic.data[0] + (c->height - 1) * c->pic.linesize[0];
-    output_end = c->pic.data[0] + (c->height) * c->pic.linesize[0];
-    while(src < c->decomp_buf + srcsize) {
-        p1 = *src++;
-        if(p1 == 0) { //Escape code
-            p2 = *src++;
-            if(p2 == 0) { //End-of-line
-                output = c->pic.data[0] + (--line) * c->pic.linesize[0];
-                if (line < 0)
-                    return -1;
-                pos = 0;
-                continue;
-            } else if(p2 == 1) { //End-of-picture
-                return 0;
-            } else if(p2 == 2) { //Skip
-                p1 = *src++;
-                p2 = *src++;
-                line -= p2;
-                if (line < 0)
-                    return -1;
-                pos += p1;
-                output = c->pic.data[0] + line * c->pic.linesize[0] + pos * (c->bpp / 8);
-                continue;
-            }
-            // Copy data
-            if (output + p2 * (c->bpp / 8) > output_end) {
-                src += p2 * (c->bpp / 8);
-                continue;
-            }
-            if ((c->bpp == 8) || (c->bpp == 24)) {
-                for(i = 0; i < p2 * (c->bpp / 8); i++) {
-                    *output++ = *src++;
-                }
-                // RLE8 copy is actually padded - and runs are not!
-                if(c->bpp == 8 && (p2 & 1)) {
-                    src++;
-                }
-            } else if (c->bpp == 16) {
-                for(i = 0; i < p2; i++) {
-                    pix16 = AV_RL16(src);
-                    src += 2;
-                    *(uint16_t*)output = pix16;
-                    output += 2;
-                }
-            } else if (c->bpp == 32) {
-                for(i = 0; i < p2; i++) {
-                    pix32 = AV_RL32(src);
-                    src += 4;
-                    *(uint32_t*)output = pix32;
-                    output += 4;
-                }
-            }
-            pos += p2;
-        } else { //Run of pixels
-            int pix[4]; //original pixel
-            switch(c->bpp){
-            case  8: pix[0] = *src++;
-                     break;
-            case 16: pix16 = AV_RL16(src);
-                     src += 2;
-                     *(uint16_t*)pix = pix16;
-                     break;
-            case 24: pix[0] = *src++;
-                     pix[1] = *src++;
-                     pix[2] = *src++;
-                     break;
-            case 32: pix32 = AV_RL32(src);
-                     src += 4;
-                     *(uint32_t*)pix = pix32;
-                     break;
-            }
-            if (output + p1 * (c->bpp / 8) > output_end)
-                continue;
-            for(i = 0; i < p1; i++) {
-                switch(c->bpp){
-                case  8: *output++ = pix[0];
-                         break;
-                case 16: *(uint16_t*)output = pix16;
-                         output += 2;
-                         break;
-                case 24: *output++ = pix[0];
-                         *output++ = pix[1];
-                         *output++ = pix[2];
-                         break;
-                case 32: *(uint32_t*)output = pix32;
-                         output += 4;
-                         break;
-                }
-            }
-            pos += p1;
-        }
-    }
-
-    av_log(c->avctx, AV_LOG_ERROR, "Camtasia warning: no End-of-picture code\n");
-    return 1;
-}
-
-/*
- *
  * Decode a frame
  *
  */
@@ -223,7 +112,7 @@
 
 
     if(zret != Z_DATA_ERROR)
-        decode_rle(c, c->zstream.avail_out);
+        ff_msrle_decode(avctx, &c->pic, c->bpp, c->decomp_buf, c->zstream.avail_out);
 
     /* make the palette available on the way out */
     if (c->avctx->pix_fmt == PIX_FMT_PAL8) {



More information about the ffmpeg-devel mailing list