libavcodec/qtrleenc.c
Go to the documentation of this file.
00001 /*
00002  * Quicktime Animation (RLE) Video Encoder
00003  * Copyright (C) 2007 Clemens Fruhwirth
00004  * Copyright (C) 2007 Alexis Ballier
00005  *
00006  * This file is based on flashsvenc.c.
00007  *
00008  * This file is part of FFmpeg.
00009  *
00010  * FFmpeg is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2.1 of the License, or (at your option) any later version.
00014  *
00015  * FFmpeg is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Lesser General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU Lesser General Public
00021  * License along with FFmpeg; if not, write to the Free Software
00022  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00023  */
00024 
00025 #include "libavutil/imgutils.h"
00026 #include "avcodec.h"
00027 #include "bytestream.h"
00028 
00030 #define MAX_RLE_BULK   127
00031 
00032 #define MAX_RLE_REPEAT 128
00033 
00034 #define MAX_RLE_SKIP   254
00035 
00036 typedef struct QtrleEncContext {
00037     AVCodecContext *avctx;
00038     AVFrame frame;
00039     int pixel_size;
00040     AVPicture previous_frame;
00041     unsigned int max_buf_size;
00042     int logical_width;
00052     signed char *rlecode_table;
00056     int *length_table;
00060     uint8_t* skip_table;
00061 } QtrleEncContext;
00062 
00063 static av_cold int qtrle_encode_init(AVCodecContext *avctx)
00064 {
00065     QtrleEncContext *s = avctx->priv_data;
00066 
00067     if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
00068         return -1;
00069     }
00070     s->avctx=avctx;
00071     s->logical_width=avctx->width;
00072 
00073     switch (avctx->pix_fmt) {
00074     case PIX_FMT_GRAY8:
00075         s->logical_width = avctx->width / 4;
00076         s->pixel_size = 4;
00077         break;
00078     case PIX_FMT_RGB555BE:
00079         s->pixel_size = 2;
00080         break;
00081     case PIX_FMT_RGB24:
00082         s->pixel_size = 3;
00083         break;
00084     case PIX_FMT_ARGB:
00085         s->pixel_size = 4;
00086         break;
00087     default:
00088         av_log(avctx, AV_LOG_ERROR, "Unsupported colorspace.\n");
00089         break;
00090     }
00091     avctx->bits_per_coded_sample = avctx->pix_fmt == PIX_FMT_GRAY8 ? 40 : s->pixel_size*8;
00092 
00093     s->rlecode_table = av_mallocz(s->logical_width);
00094     s->skip_table    = av_mallocz(s->logical_width);
00095     s->length_table  = av_mallocz((s->logical_width + 1)*sizeof(int));
00096     if (!s->skip_table || !s->length_table || !s->rlecode_table) {
00097         av_log(avctx, AV_LOG_ERROR, "Error allocating memory.\n");
00098         return -1;
00099     }
00100     if (avpicture_alloc(&s->previous_frame, avctx->pix_fmt, avctx->width, avctx->height) < 0) {
00101         av_log(avctx, AV_LOG_ERROR, "Error allocating picture\n");
00102         return -1;
00103     }
00104 
00105     s->max_buf_size = s->logical_width*s->avctx->height*s->pixel_size /* image base material */
00106                       + 15                                            /* header + footer */
00107                       + s->avctx->height*2                            /* skip code+rle end */
00108                       + s->logical_width/MAX_RLE_BULK + 1             /* rle codes */;
00109     avctx->coded_frame = &s->frame;
00110     return 0;
00111 }
00112 
00116 static void qtrle_encode_line(QtrleEncContext *s, AVFrame *p, int line, uint8_t **buf)
00117 {
00118     int width=s->logical_width;
00119     int i;
00120     signed char rlecode;
00121 
00122     /* We will use it to compute the best bulk copy sequence */
00123     unsigned int bulkcount;
00124     /* This will be the number of pixels equal to the preivous frame one's
00125      * starting from the ith pixel */
00126     unsigned int skipcount;
00127     /* This will be the number of consecutive equal pixels in the current
00128      * frame, starting from the ith one also */
00129     unsigned int av_uninit(repeatcount);
00130 
00131     /* The cost of the three different possibilities */
00132     int total_bulk_cost;
00133     int total_skip_cost;
00134     int total_repeat_cost;
00135 
00136     int temp_cost;
00137     int j;
00138 
00139     uint8_t *this_line = p->               data[0] + line*p->               linesize[0] +
00140         (width - 1)*s->pixel_size;
00141     uint8_t *prev_line = s->previous_frame.data[0] + line*s->previous_frame.linesize[0] +
00142         (width - 1)*s->pixel_size;
00143 
00144     s->length_table[width] = 0;
00145     skipcount = 0;
00146 
00147     for (i = width - 1; i >= 0; i--) {
00148 
00149         if (!s->frame.key_frame && !memcmp(this_line, prev_line, s->pixel_size))
00150             skipcount = FFMIN(skipcount + 1, MAX_RLE_SKIP);
00151         else
00152             skipcount = 0;
00153 
00154         total_skip_cost  = s->length_table[i + skipcount] + 2;
00155         s->skip_table[i] = skipcount;
00156 
00157 
00158         if (i < width - 1 && !memcmp(this_line, this_line + s->pixel_size, s->pixel_size))
00159             repeatcount = FFMIN(repeatcount + 1, MAX_RLE_REPEAT);
00160         else
00161             repeatcount = 1;
00162 
00163         total_repeat_cost = s->length_table[i + repeatcount] + 1 + s->pixel_size;
00164 
00165         /* skip code is free for the first pixel, it costs one byte for repeat and bulk copy
00166          * so let's make it aware */
00167         if (i == 0) {
00168             total_skip_cost--;
00169             total_repeat_cost++;
00170         }
00171 
00172         if (repeatcount > 1 && (skipcount == 0 || total_repeat_cost < total_skip_cost)) {
00173             /* repeat is the best */
00174             s->length_table[i]  = total_repeat_cost;
00175             s->rlecode_table[i] = -repeatcount;
00176         }
00177         else if (skipcount > 0) {
00178             /* skip is the best choice here */
00179             s->length_table[i]  = total_skip_cost;
00180             s->rlecode_table[i] = 0;
00181         }
00182         else {
00183             /* We cannot do neither skip nor repeat
00184              * thus we search for the best bulk copy to do */
00185 
00186             int limit = FFMIN(width - i, MAX_RLE_BULK);
00187 
00188             temp_cost = 1 + s->pixel_size + !i;
00189             total_bulk_cost = INT_MAX;
00190 
00191             for (j = 1; j <= limit; j++) {
00192                 if (s->length_table[i + j] + temp_cost < total_bulk_cost) {
00193                     /* We have found a better bulk copy ... */
00194                     total_bulk_cost = s->length_table[i + j] + temp_cost;
00195                     bulkcount = j;
00196                 }
00197                 temp_cost += s->pixel_size;
00198             }
00199 
00200             s->length_table[i]  = total_bulk_cost;
00201             s->rlecode_table[i] = bulkcount;
00202         }
00203 
00204         this_line -= s->pixel_size;
00205         prev_line -= s->pixel_size;
00206     }
00207 
00208     /* Good ! Now we have the best sequence for this line, let's ouput it */
00209 
00210     /* We do a special case for the first pixel so that we avoid testing it in
00211      * the whole loop */
00212 
00213     i=0;
00214     this_line = p->               data[0] + line*p->linesize[0];
00215 
00216     if (s->rlecode_table[0] == 0) {
00217         bytestream_put_byte(buf, s->skip_table[0] + 1);
00218         i += s->skip_table[0];
00219     }
00220     else bytestream_put_byte(buf, 1);
00221 
00222 
00223     while (i < width) {
00224         rlecode = s->rlecode_table[i];
00225         bytestream_put_byte(buf, rlecode);
00226         if (rlecode == 0) {
00227             /* Write a skip sequence */
00228             bytestream_put_byte(buf, s->skip_table[i] + 1);
00229             i += s->skip_table[i];
00230         }
00231         else if (rlecode > 0) {
00232             /* bulk copy */
00233             if (s->avctx->pix_fmt == PIX_FMT_GRAY8) {
00234                 int j;
00235                 // QT grayscale colorspace has 0=white and 255=black, we will
00236                 // ignore the palette that is included in the AVFrame because
00237                 // PIX_FMT_GRAY8 has defined color mapping
00238                 for (j = 0; j < rlecode*s->pixel_size; ++j)
00239                     bytestream_put_byte(buf, *(this_line + i*s->pixel_size + j) ^ 0xff);
00240             } else {
00241                 bytestream_put_buffer(buf, this_line + i*s->pixel_size, rlecode*s->pixel_size);
00242             }
00243             i += rlecode;
00244         }
00245         else {
00246             /* repeat the bits */
00247             if (s->avctx->pix_fmt == PIX_FMT_GRAY8) {
00248                 int j;
00249                 // QT grayscale colorspace has 0=white and 255=black, ...
00250                 for (j = 0; j < s->pixel_size; ++j)
00251                     bytestream_put_byte(buf, *(this_line + i*s->pixel_size + j) ^ 0xff);
00252             } else {
00253                 bytestream_put_buffer(buf, this_line + i*s->pixel_size, s->pixel_size);
00254             }
00255             i -= rlecode;
00256         }
00257     }
00258     bytestream_put_byte(buf, -1); // end RLE line
00259 }
00260 
00262 static int encode_frame(QtrleEncContext *s, AVFrame *p, uint8_t *buf)
00263 {
00264     int i;
00265     int start_line = 0;
00266     int end_line = s->avctx->height;
00267     uint8_t *orig_buf = buf;
00268 
00269     if (!s->frame.key_frame) {
00270         unsigned line_size = s->logical_width * s->pixel_size;
00271         for (start_line = 0; start_line < s->avctx->height; start_line++)
00272             if (memcmp(p->data[0] + start_line*p->linesize[0],
00273                        s->previous_frame.data[0] + start_line*s->previous_frame.linesize[0],
00274                        line_size))
00275                 break;
00276 
00277         for (end_line=s->avctx->height; end_line > start_line; end_line--)
00278             if (memcmp(p->data[0] + (end_line - 1)*p->linesize[0],
00279                        s->previous_frame.data[0] + (end_line - 1)*s->previous_frame.linesize[0],
00280                        line_size))
00281                 break;
00282     }
00283 
00284     bytestream_put_be32(&buf, 0);                         // CHUNK SIZE, patched later
00285 
00286     if ((start_line == 0 && end_line == s->avctx->height) || start_line == s->avctx->height)
00287         bytestream_put_be16(&buf, 0);                     // header
00288     else {
00289         bytestream_put_be16(&buf, 8);                     // header
00290         bytestream_put_be16(&buf, start_line);            // starting line
00291         bytestream_put_be16(&buf, 0);                     // unknown
00292         bytestream_put_be16(&buf, end_line - start_line); // lines to update
00293         bytestream_put_be16(&buf, 0);                     // unknown
00294     }
00295     for (i = start_line; i < end_line; i++)
00296         qtrle_encode_line(s, p, i, &buf);
00297 
00298     bytestream_put_byte(&buf, 0);                         // zero skip code = frame finished
00299     AV_WB32(orig_buf, buf - orig_buf);                    // patch the chunk size
00300     return buf - orig_buf;
00301 }
00302 
00303 static int qtrle_encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data)
00304 {
00305     QtrleEncContext * const s = avctx->priv_data;
00306     AVFrame *pict = data;
00307     AVFrame * const p = &s->frame;
00308     int chunksize;
00309 
00310     *p = *pict;
00311 
00312     if (buf_size < s->max_buf_size) {
00313         /* Upper bound check for compressed data */
00314         av_log(avctx, AV_LOG_ERROR, "buf_size %d <  %d\n", buf_size, s->max_buf_size);
00315         return -1;
00316     }
00317 
00318     if (avctx->gop_size == 0 || (s->avctx->frame_number % avctx->gop_size) == 0) {
00319         /* I-Frame */
00320         p->pict_type = AV_PICTURE_TYPE_I;
00321         p->key_frame = 1;
00322     } else {
00323         /* P-Frame */
00324         p->pict_type = AV_PICTURE_TYPE_P;
00325         p->key_frame = 0;
00326     }
00327 
00328     chunksize = encode_frame(s, pict, buf);
00329 
00330     /* save the current frame */
00331     av_picture_copy(&s->previous_frame, (AVPicture *)p, avctx->pix_fmt, avctx->width, avctx->height);
00332     return chunksize;
00333 }
00334 
00335 static av_cold int qtrle_encode_end(AVCodecContext *avctx)
00336 {
00337     QtrleEncContext *s = avctx->priv_data;
00338 
00339     avpicture_free(&s->previous_frame);
00340     av_free(s->rlecode_table);
00341     av_free(s->length_table);
00342     av_free(s->skip_table);
00343     return 0;
00344 }
00345 
00346 AVCodec ff_qtrle_encoder = {
00347     .name           = "qtrle",
00348     .type           = AVMEDIA_TYPE_VIDEO,
00349     .id             = CODEC_ID_QTRLE,
00350     .priv_data_size = sizeof(QtrleEncContext),
00351     .init           = qtrle_encode_init,
00352     .encode         = qtrle_encode_frame,
00353     .close          = qtrle_encode_end,
00354     .pix_fmts = (const enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB555BE, PIX_FMT_ARGB, PIX_FMT_GRAY8, PIX_FMT_NONE},
00355     .long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"),
00356 };