• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

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 Libav.
00009  *
00010  * Libav 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  * Libav 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 Libav; 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;
00051     signed char *rlecode_table;
00055     int *length_table;
00059     uint8_t* skip_table;
00060 } QtrleEncContext;
00061 
00062 static av_cold int qtrle_encode_init(AVCodecContext *avctx)
00063 {
00064     QtrleEncContext *s = avctx->priv_data;
00065 
00066     if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
00067         return -1;
00068     }
00069     s->avctx=avctx;
00070 
00071     switch (avctx->pix_fmt) {
00072     case PIX_FMT_RGB555BE:
00073         s->pixel_size = 2;
00074         break;
00075     case PIX_FMT_RGB24:
00076         s->pixel_size = 3;
00077         break;
00078     case PIX_FMT_ARGB:
00079         s->pixel_size = 4;
00080         break;
00081     default:
00082         av_log(avctx, AV_LOG_ERROR, "Unsupported colorspace.\n");
00083         break;
00084     }
00085     avctx->bits_per_coded_sample = s->pixel_size*8;
00086 
00087     s->rlecode_table = av_mallocz(s->avctx->width);
00088     s->skip_table    = av_mallocz(s->avctx->width);
00089     s->length_table  = av_mallocz((s->avctx->width + 1)*sizeof(int));
00090     if (!s->skip_table || !s->length_table || !s->rlecode_table) {
00091         av_log(avctx, AV_LOG_ERROR, "Error allocating memory.\n");
00092         return -1;
00093     }
00094     if (avpicture_alloc(&s->previous_frame, avctx->pix_fmt, avctx->width, avctx->height) < 0) {
00095         av_log(avctx, AV_LOG_ERROR, "Error allocating picture\n");
00096         return -1;
00097     }
00098 
00099     s->max_buf_size = s->avctx->width*s->avctx->height*s->pixel_size /* image base material */
00100                       + 15                                           /* header + footer */
00101                       + s->avctx->height*2                           /* skip code+rle end */
00102                       + s->avctx->width/MAX_RLE_BULK + 1             /* rle codes */;
00103     avctx->coded_frame = &s->frame;
00104     return 0;
00105 }
00106 
00110 static void qtrle_encode_line(QtrleEncContext *s, AVFrame *p, int line, uint8_t **buf)
00111 {
00112     int width=s->avctx->width;
00113     int i;
00114     signed char rlecode;
00115 
00116     /* We will use it to compute the best bulk copy sequence */
00117     unsigned int bulkcount;
00118     /* This will be the number of pixels equal to the preivous frame one's
00119      * starting from the ith pixel */
00120     unsigned int skipcount;
00121     /* This will be the number of consecutive equal pixels in the current
00122      * frame, starting from the ith one also */
00123     unsigned int av_uninit(repeatcount);
00124 
00125     /* The cost of the three different possibilities */
00126     int total_bulk_cost;
00127     int total_skip_cost;
00128     int total_repeat_cost;
00129 
00130     int temp_cost;
00131     int j;
00132 
00133     uint8_t *this_line = p->               data[0] + line*p->               linesize[0] +
00134         (width - 1)*s->pixel_size;
00135     uint8_t *prev_line = s->previous_frame.data[0] + line*s->previous_frame.linesize[0] +
00136         (width - 1)*s->pixel_size;
00137 
00138     s->length_table[width] = 0;
00139     skipcount = 0;
00140 
00141     for (i = width - 1; i >= 0; i--) {
00142 
00143         if (!s->frame.key_frame && !memcmp(this_line, prev_line, s->pixel_size))
00144             skipcount = FFMIN(skipcount + 1, MAX_RLE_SKIP);
00145         else
00146             skipcount = 0;
00147 
00148         total_skip_cost  = s->length_table[i + skipcount] + 2;
00149         s->skip_table[i] = skipcount;
00150 
00151 
00152         if (i < width - 1 && !memcmp(this_line, this_line + s->pixel_size, s->pixel_size))
00153             repeatcount = FFMIN(repeatcount + 1, MAX_RLE_REPEAT);
00154         else
00155             repeatcount = 1;
00156 
00157         total_repeat_cost = s->length_table[i + repeatcount] + 1 + s->pixel_size;
00158 
00159         /* skip code is free for the first pixel, it costs one byte for repeat and bulk copy
00160          * so let's make it aware */
00161         if (i == 0) {
00162             total_skip_cost--;
00163             total_repeat_cost++;
00164         }
00165 
00166         if (repeatcount > 1 && (skipcount == 0 || total_repeat_cost < total_skip_cost)) {
00167             /* repeat is the best */
00168             s->length_table[i]  = total_repeat_cost;
00169             s->rlecode_table[i] = -repeatcount;
00170         }
00171         else if (skipcount > 0) {
00172             /* skip is the best choice here */
00173             s->length_table[i]  = total_skip_cost;
00174             s->rlecode_table[i] = 0;
00175         }
00176         else {
00177             /* We cannot do neither skip nor repeat
00178              * thus we search for the best bulk copy to do */
00179 
00180             int limit = FFMIN(width - i, MAX_RLE_BULK);
00181 
00182             temp_cost = 1 + s->pixel_size + !i;
00183             total_bulk_cost = INT_MAX;
00184 
00185             for (j = 1; j <= limit; j++) {
00186                 if (s->length_table[i + j] + temp_cost < total_bulk_cost) {
00187                     /* We have found a better bulk copy ... */
00188                     total_bulk_cost = s->length_table[i + j] + temp_cost;
00189                     bulkcount = j;
00190                 }
00191                 temp_cost += s->pixel_size;
00192             }
00193 
00194             s->length_table[i]  = total_bulk_cost;
00195             s->rlecode_table[i] = bulkcount;
00196         }
00197 
00198         this_line -= s->pixel_size;
00199         prev_line -= s->pixel_size;
00200     }
00201 
00202     /* Good ! Now we have the best sequence for this line, let's ouput it */
00203 
00204     /* We do a special case for the first pixel so that we avoid testing it in
00205      * the whole loop */
00206 
00207     i=0;
00208     this_line = p->               data[0] + line*p->linesize[0];
00209 
00210     if (s->rlecode_table[0] == 0) {
00211         bytestream_put_byte(buf, s->skip_table[0] + 1);
00212         i += s->skip_table[0];
00213     }
00214     else bytestream_put_byte(buf, 1);
00215 
00216 
00217     while (i < width) {
00218         rlecode = s->rlecode_table[i];
00219         bytestream_put_byte(buf, rlecode);
00220         if (rlecode == 0) {
00221             /* Write a skip sequence */
00222             bytestream_put_byte(buf, s->skip_table[i] + 1);
00223             i += s->skip_table[i];
00224         }
00225         else if (rlecode > 0) {
00226             /* bulk copy */
00227             bytestream_put_buffer(buf, this_line + i*s->pixel_size, rlecode*s->pixel_size);
00228             i += rlecode;
00229         }
00230         else {
00231             /* repeat the bits */
00232             bytestream_put_buffer(buf, this_line + i*s->pixel_size, s->pixel_size);
00233             i -= rlecode;
00234         }
00235     }
00236     bytestream_put_byte(buf, -1); // end RLE line
00237 }
00238 
00240 static int encode_frame(QtrleEncContext *s, AVFrame *p, uint8_t *buf)
00241 {
00242     int i;
00243     int start_line = 0;
00244     int end_line = s->avctx->height;
00245     uint8_t *orig_buf = buf;
00246 
00247     if (!s->frame.key_frame) {
00248         unsigned line_size = s->avctx->width * s->pixel_size;
00249         for (start_line = 0; start_line < s->avctx->height; start_line++)
00250             if (memcmp(p->data[0] + start_line*p->linesize[0],
00251                        s->previous_frame.data[0] + start_line*s->previous_frame.linesize[0],
00252                        line_size))
00253                 break;
00254 
00255         for (end_line=s->avctx->height; end_line > start_line; end_line--)
00256             if (memcmp(p->data[0] + (end_line - 1)*p->linesize[0],
00257                        s->previous_frame.data[0] + (end_line - 1)*s->previous_frame.linesize[0],
00258                        line_size))
00259                 break;
00260     }
00261 
00262     bytestream_put_be32(&buf, 0);                         // CHUNK SIZE, patched later
00263 
00264     if ((start_line == 0 && end_line == s->avctx->height) || start_line == s->avctx->height)
00265         bytestream_put_be16(&buf, 0);                     // header
00266     else {
00267         bytestream_put_be16(&buf, 8);                     // header
00268         bytestream_put_be16(&buf, start_line);            // starting line
00269         bytestream_put_be16(&buf, 0);                     // unknown
00270         bytestream_put_be16(&buf, end_line - start_line); // lines to update
00271         bytestream_put_be16(&buf, 0);                     // unknown
00272     }
00273     for (i = start_line; i < end_line; i++)
00274         qtrle_encode_line(s, p, i, &buf);
00275 
00276     bytestream_put_byte(&buf, 0);                         // zero skip code = frame finished
00277     AV_WB32(orig_buf, buf - orig_buf);                    // patch the chunk size
00278     return buf - orig_buf;
00279 }
00280 
00281 static int qtrle_encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data)
00282 {
00283     QtrleEncContext * const s = avctx->priv_data;
00284     AVFrame *pict = data;
00285     AVFrame * const p = &s->frame;
00286     int chunksize;
00287 
00288     *p = *pict;
00289 
00290     if (buf_size < s->max_buf_size) {
00291         /* Upper bound check for compressed data */
00292         av_log(avctx, AV_LOG_ERROR, "buf_size %d <  %d\n", buf_size, s->max_buf_size);
00293         return -1;
00294     }
00295 
00296     if (avctx->gop_size == 0 || (s->avctx->frame_number % avctx->gop_size) == 0) {
00297         /* I-Frame */
00298         p->pict_type = AV_PICTURE_TYPE_I;
00299         p->key_frame = 1;
00300     } else {
00301         /* P-Frame */
00302         p->pict_type = AV_PICTURE_TYPE_P;
00303         p->key_frame = 0;
00304     }
00305 
00306     chunksize = encode_frame(s, pict, buf);
00307 
00308     /* save the current frame */
00309     av_picture_copy(&s->previous_frame, (AVPicture *)p, avctx->pix_fmt, avctx->width, avctx->height);
00310     return chunksize;
00311 }
00312 
00313 static av_cold int qtrle_encode_end(AVCodecContext *avctx)
00314 {
00315     QtrleEncContext *s = avctx->priv_data;
00316 
00317     avpicture_free(&s->previous_frame);
00318     av_free(s->rlecode_table);
00319     av_free(s->length_table);
00320     av_free(s->skip_table);
00321     return 0;
00322 }
00323 
00324 AVCodec ff_qtrle_encoder = {
00325     .name           = "qtrle",
00326     .type           = AVMEDIA_TYPE_VIDEO,
00327     .id             = CODEC_ID_QTRLE,
00328     .priv_data_size = sizeof(QtrleEncContext),
00329     .init           = qtrle_encode_init,
00330     .encode         = qtrle_encode_frame,
00331     .close          = qtrle_encode_end,
00332     .pix_fmts = (const enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB555BE, PIX_FMT_ARGB, PIX_FMT_NONE},
00333     .long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"),
00334 };
Generated on Thu Jan 24 2013 17:08:53 for Libav by doxygen 1.7.1