Libav 0.7.1
|
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 "qtrle", 00326 AVMEDIA_TYPE_VIDEO, 00327 CODEC_ID_QTRLE, 00328 sizeof(QtrleEncContext), 00329 qtrle_encode_init, 00330 qtrle_encode_frame, 00331 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 };