libavcodec/qtrleenc.c
d3b7406c
 /*
  * Quicktime Animation (RLE) Video Encoder
  * Copyright (C) 2007 Clemens Fruhwirth
  * Copyright (C) 2007 Alexis Ballier
  *
4f31c990
  * This file is based on flashsvenc.c.
d3b7406c
  *
4f31c990
  * This file is part of FFmpeg.
d3b7406c
  *
  * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
3943bd09
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
d3b7406c
  *
  * 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
  */
 
7ffe76e5
 #include "libavutil/imgutils.h"
d3b7406c
 #include "avcodec.h"
 #include "bytestream.h"
21b46747
 #include "internal.h"
d3b7406c
 
 /** Maximum RLE code for bulk copy */
 #define MAX_RLE_BULK   127
 /** Maximum RLE code for repeat */
 #define MAX_RLE_REPEAT 128
 /** Maximum RLE code for skip */
 #define MAX_RLE_SKIP   254
 
 typedef struct QtrleEncContext {
     AVCodecContext *avctx;
     int pixel_size;
901f9c0a
     AVFrame *previous_frame;
d3b7406c
     unsigned int max_buf_size;
ce10e858
     int logical_width;
d3b7406c
     /**
      * This array will contain at ith position the value of the best RLE code
      * if the line started at pixel i
      * There can be 3 values :
      * skip (0)     : skip as much as possible pixels because they are equal to the
      *                previous frame ones
      * repeat (<-1) : repeat that pixel -rle_code times, still as much as
      *                possible
      * copy (>0)    : copy the raw next rle_code pixels */
     signed char *rlecode_table;
     /**
      * This array will contain the length of the best rle encoding of the line
      * starting at ith pixel */
     int *length_table;
     /**
      * Will contain at ith position the number of consecutive pixels equal to the previous
      * frame starting from pixel i */
     uint8_t* skip_table;
efc618af
 
     /** Encoded frame is a key frame */
     int key_frame;
d3b7406c
 } QtrleEncContext;
 
d48c2063
 static av_cold int qtrle_encode_end(AVCodecContext *avctx)
 {
     QtrleEncContext *s = avctx->priv_data;
 
901f9c0a
     av_frame_free(&s->previous_frame);
d48c2063
     av_free(s->rlecode_table);
     av_free(s->length_table);
     av_free(s->skip_table);
     return 0;
 }
 
98a6fff9
 static av_cold int qtrle_encode_init(AVCodecContext *avctx)
d3b7406c
 {
     QtrleEncContext *s = avctx->priv_data;
 
e16f217c
     if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
208c5a08
         return AVERROR(EINVAL);
d3b7406c
     }
     s->avctx=avctx;
ce10e858
     s->logical_width=avctx->width;
d3b7406c
 
     switch (avctx->pix_fmt) {
ac627b3d
     case AV_PIX_FMT_GRAY8:
c69defd4
         if (avctx->width % 4) {
             av_log(avctx, AV_LOG_ERROR, "Width not being a multiple of 4 is not supported\n");
             return AVERROR(EINVAL);
         }
ce10e858
         s->logical_width = avctx->width / 4;
         s->pixel_size = 4;
         break;
716d413c
     case AV_PIX_FMT_RGB555BE:
d3b7406c
         s->pixel_size = 2;
57937d61
         break;
716d413c
     case AV_PIX_FMT_RGB24:
d3b7406c
         s->pixel_size = 3;
         break;
716d413c
     case AV_PIX_FMT_ARGB:
287fff26
         s->pixel_size = 4;
         break;
d3b7406c
     default:
         av_log(avctx, AV_LOG_ERROR, "Unsupported colorspace.\n");
         break;
     }
ac627b3d
     avctx->bits_per_coded_sample = avctx->pix_fmt == AV_PIX_FMT_GRAY8 ? 40 : s->pixel_size*8;
d3b7406c
 
ce10e858
     s->rlecode_table = av_mallocz(s->logical_width);
     s->skip_table    = av_mallocz(s->logical_width);
60c8c714
     s->length_table  = av_mallocz_array(s->logical_width + 1, sizeof(int));
d3b7406c
     if (!s->skip_table || !s->length_table || !s->rlecode_table) {
         av_log(avctx, AV_LOG_ERROR, "Error allocating memory.\n");
208c5a08
         return AVERROR(ENOMEM);
d3b7406c
     }
901f9c0a
     s->previous_frame = av_frame_alloc();
     if (!s->previous_frame) {
d3b7406c
         av_log(avctx, AV_LOG_ERROR, "Error allocating picture\n");
9c3f75c2
         return AVERROR(ENOMEM);
d3b7406c
     }
 
e2cc39b6
     s->max_buf_size = s->logical_width*s->avctx->height*s->pixel_size*2 /* image base material */
ce10e858
                       + 15                                            /* header + footer */
                       + s->avctx->height*2                            /* skip code+rle end */
                       + s->logical_width/MAX_RLE_BULK + 1             /* rle codes */;
d48c2063
 
d3b7406c
     return 0;
 }
 
 /**
49bd8e4b
  * Compute the best RLE sequence for a line
d3b7406c
  */
21b46747
 static void qtrle_encode_line(QtrleEncContext *s, const AVFrame *p, int line, uint8_t **buf)
d3b7406c
 {
ce10e858
     int width=s->logical_width;
d3b7406c
     int i;
     signed char rlecode;
 
41ed7ab4
     /* This will be the number of pixels equal to the previous frame one's
d3b7406c
      * starting from the ith pixel */
     unsigned int skipcount;
     /* This will be the number of consecutive equal pixels in the current
      * frame, starting from the ith one also */
8b18288c
     unsigned int av_uninit(repeatcount);
d3b7406c
 
     /* The cost of the three different possibilities */
     int total_skip_cost;
     int total_repeat_cost;
 
239b88c2
     int base_bulk_cost;
     int lowest_bulk_cost;
     int lowest_bulk_cost_index;
     int sec_lowest_bulk_cost;
     int sec_lowest_bulk_cost_index;
d3b7406c
 
9867a14f
     uint8_t *this_line = p->               data[0] + line*p->               linesize[0] +
         (width - 1)*s->pixel_size;
901f9c0a
     uint8_t *prev_line = s->previous_frame->data[0] + line * s->previous_frame->linesize[0] +
9867a14f
         (width - 1)*s->pixel_size;
d3b7406c
 
     s->length_table[width] = 0;
     skipcount = 0;
 
239b88c2
     /* Initial values */
     lowest_bulk_cost = INT_MAX / 2;
     lowest_bulk_cost_index = width;
     sec_lowest_bulk_cost = INT_MAX / 2;
     sec_lowest_bulk_cost_index = width;
 
     base_bulk_cost = 1 + s->pixel_size;
 
d3b7406c
     for (i = width - 1; i >= 0; i--) {
 
239b88c2
         int prev_bulk_cost;
 
         /* If our lowest bulk cost index is too far away, replace it
          * with the next lowest bulk cost */
         if (FFMIN(width, i + MAX_RLE_BULK) < lowest_bulk_cost_index) {
             lowest_bulk_cost = sec_lowest_bulk_cost;
             lowest_bulk_cost_index = sec_lowest_bulk_cost_index;
 
             sec_lowest_bulk_cost = INT_MAX / 2;
             sec_lowest_bulk_cost_index = width;
         }
 
         /* Deal with the first pixel's bulk cost */
         if (!i) {
             base_bulk_cost++;
             lowest_bulk_cost++;
             sec_lowest_bulk_cost++;
         }
 
         /* Look at the bulk cost of the previous loop and see if it is
          * a new lower bulk cost */
         prev_bulk_cost = s->length_table[i + 1] + base_bulk_cost;
         if (prev_bulk_cost <= sec_lowest_bulk_cost) {
             /* If it's lower than the 2nd lowest, then it may be lower
              * than the lowest */
             if (prev_bulk_cost <= lowest_bulk_cost) {
 
                 /* If we have found a new lowest bulk cost,
                  * then the 2nd lowest bulk cost is now farther than the
                  * lowest bulk cost, and will never be used */
                 sec_lowest_bulk_cost = INT_MAX / 2;
 
                 lowest_bulk_cost = prev_bulk_cost;
                 lowest_bulk_cost_index = i + 1;
             } else {
                 /* Then it must be the 2nd lowest bulk cost */
                 sec_lowest_bulk_cost = prev_bulk_cost;
                 sec_lowest_bulk_cost_index = i + 1;
             }
         }
 
efc618af
         if (!s->key_frame && !memcmp(this_line, prev_line, s->pixel_size))
d3b7406c
             skipcount = FFMIN(skipcount + 1, MAX_RLE_SKIP);
         else
             skipcount = 0;
 
         total_skip_cost  = s->length_table[i + skipcount] + 2;
         s->skip_table[i] = skipcount;
 
 
         if (i < width - 1 && !memcmp(this_line, this_line + s->pixel_size, s->pixel_size))
             repeatcount = FFMIN(repeatcount + 1, MAX_RLE_REPEAT);
         else
             repeatcount = 1;
 
         total_repeat_cost = s->length_table[i + repeatcount] + 1 + s->pixel_size;
 
         /* skip code is free for the first pixel, it costs one byte for repeat and bulk copy
          * so let's make it aware */
         if (i == 0) {
             total_skip_cost--;
             total_repeat_cost++;
         }
 
         if (repeatcount > 1 && (skipcount == 0 || total_repeat_cost < total_skip_cost)) {
             /* repeat is the best */
             s->length_table[i]  = total_repeat_cost;
             s->rlecode_table[i] = -repeatcount;
         }
         else if (skipcount > 0) {
             /* skip is the best choice here */
             s->length_table[i]  = total_skip_cost;
             s->rlecode_table[i] = 0;
         }
         else {
             /* We cannot do neither skip nor repeat
239b88c2
              * thus we use the best bulk copy  */
d3b7406c
 
239b88c2
             s->length_table[i]  = lowest_bulk_cost;
             s->rlecode_table[i] = lowest_bulk_cost_index - i;
d3b7406c
 
         }
 
239b88c2
         /* These bulk costs increase every iteration */
         lowest_bulk_cost += s->pixel_size;
         sec_lowest_bulk_cost += s->pixel_size;
 
d3b7406c
         this_line -= s->pixel_size;
         prev_line -= s->pixel_size;
     }
 
41ed7ab4
     /* Good! Now we have the best sequence for this line, let's output it. */
d3b7406c
 
     /* We do a special case for the first pixel so that we avoid testing it in
      * the whole loop */
 
     i=0;
     this_line = p->               data[0] + line*p->linesize[0];
 
     if (s->rlecode_table[0] == 0) {
         bytestream_put_byte(buf, s->skip_table[0] + 1);
         i += s->skip_table[0];
     }
     else bytestream_put_byte(buf, 1);
 
 
     while (i < width) {
         rlecode = s->rlecode_table[i];
         bytestream_put_byte(buf, rlecode);
         if (rlecode == 0) {
             /* Write a skip sequence */
             bytestream_put_byte(buf, s->skip_table[i] + 1);
             i += s->skip_table[i];
         }
         else if (rlecode > 0) {
             /* bulk copy */
ac627b3d
             if (s->avctx->pix_fmt == AV_PIX_FMT_GRAY8) {
9e4cb03a
                 int j;
ce10e858
                 // QT grayscale colorspace has 0=white and 255=black, we will
                 // ignore the palette that is included in the AVFrame because
ac627b3d
                 // AV_PIX_FMT_GRAY8 has defined color mapping
9e4cb03a
                 for (j = 0; j < rlecode*s->pixel_size; ++j)
ce10e858
                     bytestream_put_byte(buf, *(this_line + i*s->pixel_size + j) ^ 0xff);
             } else {
                 bytestream_put_buffer(buf, this_line + i*s->pixel_size, rlecode*s->pixel_size);
             }
d3b7406c
             i += rlecode;
         }
         else {
             /* repeat the bits */
ac627b3d
             if (s->avctx->pix_fmt == AV_PIX_FMT_GRAY8) {
9e4cb03a
                 int j;
ce10e858
                 // QT grayscale colorspace has 0=white and 255=black, ...
9e4cb03a
                 for (j = 0; j < s->pixel_size; ++j)
ce10e858
                     bytestream_put_byte(buf, *(this_line + i*s->pixel_size + j) ^ 0xff);
             } else {
                 bytestream_put_buffer(buf, this_line + i*s->pixel_size, s->pixel_size);
             }
d3b7406c
             i -= rlecode;
         }
     }
     bytestream_put_byte(buf, -1); // end RLE line
 }
 
49bd8e4b
 /** Encode frame including header */
21b46747
 static int encode_frame(QtrleEncContext *s, const AVFrame *p, uint8_t *buf)
d3b7406c
 {
     int i;
     int start_line = 0;
     int end_line = s->avctx->height;
     uint8_t *orig_buf = buf;
 
efc618af
     if (!s->key_frame) {
ce10e858
         unsigned line_size = s->logical_width * s->pixel_size;
d3b7406c
         for (start_line = 0; start_line < s->avctx->height; start_line++)
             if (memcmp(p->data[0] + start_line*p->linesize[0],
901f9c0a
                        s->previous_frame->data[0] + start_line * s->previous_frame->linesize[0],
9867a14f
                        line_size))
d3b7406c
                 break;
 
         for (end_line=s->avctx->height; end_line > start_line; end_line--)
             if (memcmp(p->data[0] + (end_line - 1)*p->linesize[0],
901f9c0a
                        s->previous_frame->data[0] + (end_line - 1) * s->previous_frame->linesize[0],
9867a14f
                        line_size))
d3b7406c
                 break;
     }
 
     bytestream_put_be32(&buf, 0);                         // CHUNK SIZE, patched later
 
4a9dfdc1
     if ((start_line == 0 && end_line == s->avctx->height) || start_line == s->avctx->height)
d3b7406c
         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++)
         qtrle_encode_line(s, p, i, &buf);
 
     bytestream_put_byte(&buf, 0);                         // zero skip code = frame finished
     AV_WB32(orig_buf, buf - orig_buf);                    // patch the chunk size
     return buf - orig_buf;
 }
 
21b46747
 static int qtrle_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
                               const AVFrame *pict, int *got_packet)
d3b7406c
 {
     QtrleEncContext * const s = avctx->priv_data;
21b46747
     int ret;
d3b7406c
 
e36db49b
     if ((ret = ff_alloc_packet2(avctx, pkt, s->max_buf_size, 0)) < 0)
21b46747
         return ret;
d3b7406c
 
     if (avctx->gop_size == 0 || (s->avctx->frame_number % avctx->gop_size) == 0) {
         /* I-Frame */
efc618af
         s->key_frame = 1;
d3b7406c
     } else {
         /* P-Frame */
efc618af
         s->key_frame = 0;
d3b7406c
     }
 
21b46747
     pkt->size = encode_frame(s, pict, pkt->data);
d3b7406c
 
     /* save the current frame */
901f9c0a
     av_frame_unref(s->previous_frame);
     ret = av_frame_ref(s->previous_frame, pict);
     if (ret < 0) {
         av_log(avctx, AV_LOG_ERROR, "cannot add reference\n");
         return ret;
     }
21b46747
 
40cf1bba
 #if FF_API_CODED_FRAME
 FF_DISABLE_DEPRECATION_WARNINGS
efc618af
     avctx->coded_frame->key_frame = s->key_frame;
85185578
     avctx->coded_frame->pict_type = s->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
40cf1bba
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
efc618af
 
     if (s->key_frame)
21b46747
         pkt->flags |= AV_PKT_FLAG_KEY;
     *got_packet = 1;
 
     return 0;
d3b7406c
 }
 
e7e2df27
 AVCodec ff_qtrle_encoder = {
ec6402b7
     .name           = "qtrle",
b2bed932
     .long_name      = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"),
ec6402b7
     .type           = AVMEDIA_TYPE_VIDEO,
36ef5369
     .id             = AV_CODEC_ID_QTRLE,
ec6402b7
     .priv_data_size = sizeof(QtrleEncContext),
     .init           = qtrle_encode_init,
21b46747
     .encode2        = qtrle_encode_frame,
ec6402b7
     .close          = qtrle_encode_end,
716d413c
     .pix_fmts       = (const enum AVPixelFormat[]){
ac627b3d
         AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB555BE, AV_PIX_FMT_ARGB, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
00c3b67b
     },
d3b7406c
 };