Index: libavcodec/qtrleenc.c
===================================================================
--- libavcodec/qtrleenc.c	(revision 0)
+++ libavcodec/qtrleenc.c	(revision 0)
@@ -0,0 +1,325 @@
+/*
+ * Quicktime Animation (RLE) Video Encoder
+ * Copyright (C) 2007 Clemens Fruhwirth
+ *
+ * This file is part of FFmpeg.
+ *
+ * This file is based on flashsvenc.c,
+ * Copyright (C) 2004 Alex Beregszaszi
+ * Copyright (C) 2006 Benjamin Larsson
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License, version 2.1, as published by the Free Software Foundation
+ *
+ * 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
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "avcodec.h"
+#include "bytestream.h"
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+/* Maximum RLE codes for bulk copy and repeat */
+#define MAX_RLE_BULK   127
+#define MAX_RLE_REPEAT 128
+
+typedef struct QtrleEncContext {
+    AVCodecContext *avctx;
+    uint8_t *previous_frame;
+    AVFrame frame;
+    int image_width, image_height;
+    int pixel_size;
+    uint32_t frame_number;
+    int max_buf_size;
+} QtrleEncContext;
+
+static int qtrle_encode_init(AVCodecContext *avctx)
+{
+    QtrleEncContext *s = (QtrleEncContext *)avctx->priv_data;
+
+    if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) {
+        return -1;
+    }
+    s->avctx=avctx;
+    s->frame_number = 0;
+    s->image_width = avctx->width;
+    s->image_height = avctx->height;
+
+    switch (avctx->pix_fmt) {
+    case PIX_FMT_RGB555:
+        s->pixel_size = 2;
+        break;
+    case PIX_FMT_RGB24:
+        s->pixel_size = 3;
+        break;
+    default:
+        av_log (avctx, AV_LOG_ERROR, "Unsupported colorspace.\n");
+        break;
+    }
+    avctx->bits_per_sample = s->pixel_size*8;
+    
+    s->previous_frame = av_mallocz(s->image_width*s->pixel_size*s->image_height);
+    if (!s->previous_frame) {
+        av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
+        return -1;
+    }
+    s->max_buf_size=(s->image_width*s->image_height*s->pixel_size  /* image base material */
+                     + 15                                          /* header + footer */
+                     + s->image_height*2                           /* skip code+rle end */
+                     + s->image_width%MAX_RLE_BULK                 /* rle codes */);
+    return 0;
+}
+
+static void put_pixel(QtrleEncContext *s, uint8_t *pixpointer, uint8_t **buf)
+{
+    switch (s->pixel_size) {
+    case 2:
+        bytestream_put_be16(buf,*((uint16_t *)pixpointer));
+        break;
+    case 3:
+        bytestream_put_buffer(buf, pixpointer, s->pixel_size);
+        break;
+    default:
+        /* Internal Error. Die? */
+        av_log(s->avctx, AV_LOG_ERROR, "Internal Error. Unknown pixel size in qtrleenc.c:put_pixel.\n");
+        break;
+    }
+}
+
+/* Scans two memory stripes in junks for equality */
+static int scan_equal(uint8_t *a, uint8_t *b, int limit, int junksize)
+{
+    int orig_limit=limit;
+    while(limit && (memcmp(a,b,junksize) == 0)) {
+	a+=junksize;
+	b+=junksize;
+	limit--;
+    }
+    return orig_limit-limit;
+}
+
+/* Scans two memory stripes in junks for !equlity */
+static int scan_unequal(uint8_t *a, uint8_t *b, int limit, int junksize)
+{
+    int orig_limit=limit;
+    while(limit && (memcmp(a,b,junksize) != 0)) {
+        a+=junksize;
+        b+=junksize;
+        limit--;
+    }
+    return orig_limit-limit;
+}
+
+/* This is the RLE encoder with bulk copy instruction */
+static void encode_rle(QtrleEncContext *s, uint8_t *pix, uint8_t **buf, int rlepix)
+{
+   while(rlepix) {
+       /* Number of subsequent non-unique pixels (at least 1) */
+       int equals=1+scan_equal(pix,
+                               pix+s->pixel_size,
+                               min(rlepix-1,MAX_RLE_REPEAT-1),
+                               s->pixel_size);
+       if(equals == 1) {
+           /* Output bulk copy */
+           /* Scan how much unique pixels to include in this bulk copy */
+           signed char rlecode=scan_unequal(pix,
+                                            pix+s->pixel_size,
+                                            min(rlepix-1,MAX_RLE_BULK),
+                                            s->pixel_size);
+           rlepix-=rlecode;
+           /* Ugly corner case */
+           if(rlepix==1 && rlecode < MAX_RLE_BULK) {
+               rlecode++; rlepix--;
+           }
+           bytestream_put_byte(buf, rlecode);
+           while(rlecode--) {
+               put_pixel(s,pix,buf);
+               pix+=s->pixel_size;
+           }
+       } else {
+           /* Output repeat code */
+           signed char rlecode=-equals;
+           bytestream_put_byte(buf, rlecode);
+           put_pixel(s,pix,buf);
+           pix+=equals*s->pixel_size;
+           rlepix-=equals;
+       }
+   }
+}
+
+static void generate_skipcodes(uint8_t **buf, int skippix)
+{
+    while(skippix) {
+        int skipped=skippix<254?skippix:254;
+        bytestream_put_byte(buf, skipped+1); // skip code
+        bytestream_put_byte(buf, 0);         // RLE code 0: another skip code is coming.
+        skippix-=skipped;
+    }
+    (*buf)--;                              // Remove last RLE code announcing a skip code
+}
+
+/* Dump line with skip codes */
+static void dump_line_incremental(QtrleEncContext *s, AVFrame *p, int line, uint8_t **buf)
+{
+    uint8_t *this_line = p->data[0]+(line*p->linesize[0]);
+    uint8_t *prev_line = s->previous_frame+(line*p->linesize[0]);
+    int i=s->image_width;
+
+    while(i) {
+        int skip_pix;
+        int encode_pix;
+
+	skip_pix=scan_equal(this_line, prev_line, i, s->pixel_size);
+        i-=skip_pix;
+
+	this_line+=skip_pix*s->pixel_size;
+        prev_line+=skip_pix*s->pixel_size;
+
+	encode_pix=scan_unequal(this_line, prev_line, i, s->pixel_size);
+        i-=encode_pix;
+
+        /* Output skip byte */
+        /* special case optimization: nothing left to encode, hence
+           choose minimal skip code as does not matter. */
+        if(i==0 && encode_pix == 0)
+            generate_skipcodes(buf, 1);
+        else
+            generate_skipcodes(buf, skip_pix);
+
+	/* Output RLE lines */
+        encode_rle(s, this_line, buf, encode_pix);
+
+        this_line+=encode_pix*s->pixel_size;
+        prev_line+=encode_pix*s->pixel_size;
+
+        bytestream_put_byte(buf, 0);             // RLE code 0: another skip code is coming.
+    }
+    (*buf)--;                                  // Remove last incorrect RLE code, announcing a skip code
+    bytestream_put_byte(buf, (signed char)-1); // end RLE line
+}
+
+static void dump_line_complete(QtrleEncContext *s, AVFrame *p, int line, uint8_t **buf)
+{
+    bytestream_put_byte(buf, 1); // nothing to skip
+    encode_rle(s, p->data[0]+(line*p->linesize[0]), buf, s->image_width);
+    bytestream_put_byte(buf, (signed char)-1); // end RLE line
+}
+
+/* Dumps frame including header */
+static int dump_frame(QtrleEncContext *s, AVFrame *p, uint8_t *buf, int incremental)
+{
+    int i;
+    int start_line=0;
+    int end_line=s->image_height;
+    uint8_t *orig_buf=buf;
+
+    if(incremental) {
+        for(start_line=0; start_line < s->image_height; start_line++)
+            if(memcmp(p->data[0]+(start_line*p->linesize[0]),
+                      s->previous_frame+(start_line*p->linesize[0]),
+                      p->linesize[0]))
+                break;
+
+        for(end_line=s->image_height; end_line > start_line; end_line--)
+            if(memcmp(p->data[0]+(end_line-1)*p->linesize[0],
+                      s->previous_frame+(end_line-1)*p->linesize[0],
+                      p->linesize[0]))
+                break;
+    }
+
+    bytestream_put_be32(&buf, 0);                     // CHUNK SIZE, patched later
+
+    if((start_line==0 && end_line == s->image_height) || start_line==s->image_height)
+        bytestream_put_be16(&buf, 0);                   // header
+    else {
+        bytestream_put_be16(&buf, 8);                   // header
+        bytestream_put_be16(&buf, start_line);          // starting line
+        bytestream_put_be16(&buf, 0);                   // unknown
+        bytestream_put_be16(&buf, end_line-start_line); // lines to update
+        bytestream_put_be16(&buf, 0);                   // unknown
+    }
+    for(i=start_line; i < end_line; i++) {
+        if(incremental)
+            dump_line_incremental(s, p, i, &buf);
+        else {
+            dump_line_complete(s, p, i, &buf);
+        }
+    }
+    bytestream_put_byte(&buf, 0);                     // zero skip code = frame finished
+    bytestream_put_be32(&orig_buf,buf-orig_buf);      // patch the chunk size
+    return (buf-orig_buf)+4;
+}
+
+static int qtrle_encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data)
+{
+    QtrleEncContext * const s = (QtrleEncContext *)avctx->priv_data;
+    AVFrame *pict = data;
+    AVFrame * const p = &s->frame;
+    int chunksize;
+
+    *p = *pict;
+
+    if (buf_size < s->max_buf_size) {
+        /* Upper bound check for compressed data */
+        av_log(avctx, AV_LOG_ERROR, "buf_size %d <  %d\n", buf_size, s->max_buf_size);
+        return -1;
+    }
+
+    if (avctx->gop_size == 0 || (s->frame_number % avctx->gop_size) == 0) {
+        /* I-Frame */
+        p->pict_type = FF_I_TYPE;
+        p->key_frame = 1;
+        chunksize = dump_frame(s, pict, buf, 0);
+    } else {
+        /* P-Frame */
+        p->pict_type = FF_P_TYPE;
+        p->key_frame = 0;
+        chunksize = dump_frame(s, pict, buf, 1);
+    }
+
+    /* save the current frame */
+    memcpy(s->previous_frame, p->data[0], s->image_height*p->linesize[0]);
+
+    avctx->coded_frame = p;
+
+    //    av_log(s->avctx, AV_LOG_INFO, "chunksize=%d\n",chunksize);
+    s->frame_number++;
+    return chunksize;
+}
+
+static int qtrle_encode_end(AVCodecContext *avctx)
+{
+    QtrleEncContext *s = (QtrleEncContext *)avctx->priv_data;
+
+    av_free(s->previous_frame);
+    return 0;
+}
+AVCodec qtrle_encoder = {
+    "qtrle",
+    CODEC_TYPE_VIDEO,
+    CODEC_ID_QTRLE,
+    sizeof(QtrleEncContext),
+    qtrle_encode_init,
+    qtrle_encode_frame,
+    qtrle_encode_end,
+    .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB555, -1},
+};
+
+/* Local Variables: */
+/* c-basic-offset:4 */
+/* indent-tabs-mode:nil */
+/* End: */
Index: libavcodec/qtrle.c
===================================================================
--- libavcodec/qtrle.c	(revision 7881)
+++ libavcodec/qtrle.c	(working copy)
@@ -40,6 +40,8 @@
 #include "common.h"
 #include "avcodec.h"
 #include "dsputil.h"
+#include "bitstream.h"
+#include "bytestream.h"
 
 typedef struct QtrleContext {
 
@@ -49,9 +51,11 @@
 
     unsigned char *buf;
     int size;
+    uint8_t *previous_frame;
 
 } QtrleContext;
 
+
 #define CHECK_STREAM_PTR(n) \
   if ((stream_ptr + n) > s->size) { \
     av_log (s->avctx, AV_LOG_INFO, "Problem: stream_ptr out of bounds (%d >= %d)\n", \
@@ -627,4 +631,3 @@
     qtrle_decode_frame,
     CODEC_CAP_DR1,
 };
-
Index: libavcodec/allcodecs.c
===================================================================
--- libavcodec/allcodecs.c	(revision 7881)
+++ libavcodec/allcodecs.c	(working copy)
@@ -109,7 +109,7 @@
     REGISTER_ENCODER(PPM, ppm);
     REGISTER_DECODER(QDRAW, qdraw);
     REGISTER_DECODER(QPEG, qpeg);
-    REGISTER_DECODER(QTRLE, qtrle);
+    REGISTER_ENCDEC(QTRLE, qtrle);
     REGISTER_ENCDEC (RAWVIDEO, rawvideo);
     REGISTER_DECODER(ROQ, roq);
     REGISTER_DECODER(RPZA, rpza);
Index: libavcodec/Makefile
===================================================================
--- libavcodec/Makefile	(revision 7881)
+++ libavcodec/Makefile	(working copy)
@@ -114,6 +114,7 @@
 OBJS-$(CONFIG_QDRAW_DECODER)           += qdrw.o
 OBJS-$(CONFIG_QPEG_DECODER)            += qpeg.o
 OBJS-$(CONFIG_QTRLE_DECODER)           += qtrle.o
+OBJS-$(CONFIG_QTRLE_ENCODER)           += qtrleenc.o
 OBJS-$(CONFIG_RA_144_DECODER)          += ra144.o
 OBJS-$(CONFIG_RA_288_DECODER)          += ra288.o
 OBJS-$(CONFIG_ROQ_DECODER)             += roqvideo.o
Index: libavcodec/avcodec.h
===================================================================
--- libavcodec/avcodec.h	(revision 7881)
+++ libavcodec/avcodec.h	(working copy)
@@ -2273,6 +2273,7 @@
 extern AVCodec qdraw_decoder;
 extern AVCodec qpeg_decoder;
 extern AVCodec qtrle_decoder;
+extern AVCodec qtrle_encoder;
 extern AVCodec ra_144_decoder;
 extern AVCodec ra_288_decoder;
 extern AVCodec roq_decoder;
Index: libavformat/movenc.c
===================================================================
--- libavformat/movenc.c	(revision 7881)
+++ libavformat/movenc.c	(working copy)
@@ -533,6 +533,7 @@
     { CODEC_ID_H263, MKTAG('h', '2', '6', '3') },
     { CODEC_ID_H263, MKTAG('s', '2', '6', '3') },
     { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
+    { CODEC_ID_QTRLE, MKTAG('r', 'l', 'e', ' ') },
     /* special handling in mov_find_video_codec_tag */
     { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') }, /* DV NTSC */
     { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 'p') }, /* DV PAL */
