00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 #include "libavutil/imgutils.h"
00026 #include "avcodec.h"
00027 #include "bytestream.h"
00028 #include "internal.h"
00029 
00031 #define MAX_RLE_BULK   127
00032 
00033 #define MAX_RLE_REPEAT 128
00034 
00035 #define MAX_RLE_SKIP   254
00036 
00037 typedef struct QtrleEncContext {
00038     AVCodecContext *avctx;
00039     AVFrame frame;
00040     int pixel_size;
00041     AVPicture previous_frame;
00042     unsigned int max_buf_size;
00043     int logical_width;
00053     signed char *rlecode_table;
00057     int *length_table;
00061     uint8_t* skip_table;
00062 } QtrleEncContext;
00063 
00064 static av_cold int qtrle_encode_init(AVCodecContext *avctx)
00065 {
00066     QtrleEncContext *s = avctx->priv_data;
00067     int ret;
00068 
00069     if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
00070         return AVERROR(EINVAL);
00071     }
00072     s->avctx=avctx;
00073     s->logical_width=avctx->width;
00074 
00075     switch (avctx->pix_fmt) {
00076     case PIX_FMT_GRAY8:
00077         s->logical_width = avctx->width / 4;
00078         s->pixel_size = 4;
00079         break;
00080     case PIX_FMT_RGB555BE:
00081         s->pixel_size = 2;
00082         break;
00083     case PIX_FMT_RGB24:
00084         s->pixel_size = 3;
00085         break;
00086     case PIX_FMT_ARGB:
00087         s->pixel_size = 4;
00088         break;
00089     default:
00090         av_log(avctx, AV_LOG_ERROR, "Unsupported colorspace.\n");
00091         break;
00092     }
00093     avctx->bits_per_coded_sample = avctx->pix_fmt == PIX_FMT_GRAY8 ? 40 : s->pixel_size*8;
00094 
00095     s->rlecode_table = av_mallocz(s->logical_width);
00096     s->skip_table    = av_mallocz(s->logical_width);
00097     s->length_table  = av_mallocz((s->logical_width + 1)*sizeof(int));
00098     if (!s->skip_table || !s->length_table || !s->rlecode_table) {
00099         av_log(avctx, AV_LOG_ERROR, "Error allocating memory.\n");
00100         return AVERROR(ENOMEM);
00101     }
00102     if ((ret = avpicture_alloc(&s->previous_frame, avctx->pix_fmt, avctx->width, avctx->height)) < 0) {
00103         av_log(avctx, AV_LOG_ERROR, "Error allocating picture\n");
00104         return ret;
00105     }
00106 
00107     s->max_buf_size = s->logical_width*s->avctx->height*s->pixel_size*2 
00108                       + 15                                            
00109                       + s->avctx->height*2                            
00110                       + s->logical_width/MAX_RLE_BULK + 1             ;
00111     avctx->coded_frame = &s->frame;
00112     return 0;
00113 }
00114 
00118 static void qtrle_encode_line(QtrleEncContext *s, const AVFrame *p, int line, uint8_t **buf)
00119 {
00120     int width=s->logical_width;
00121     int i;
00122     signed char rlecode;
00123 
00124     
00125     unsigned int av_uninit(bulkcount);
00126     
00127 
00128     unsigned int skipcount;
00129     
00130 
00131     unsigned int av_uninit(repeatcount);
00132 
00133     
00134     int total_bulk_cost;
00135     int total_skip_cost;
00136     int total_repeat_cost;
00137 
00138     int temp_cost;
00139     int j;
00140 
00141     uint8_t *this_line = p->               data[0] + line*p->               linesize[0] +
00142         (width - 1)*s->pixel_size;
00143     uint8_t *prev_line = s->previous_frame.data[0] + line*s->previous_frame.linesize[0] +
00144         (width - 1)*s->pixel_size;
00145 
00146     s->length_table[width] = 0;
00147     skipcount = 0;
00148 
00149     for (i = width - 1; i >= 0; i--) {
00150 
00151         if (!s->frame.key_frame && !memcmp(this_line, prev_line, s->pixel_size))
00152             skipcount = FFMIN(skipcount + 1, MAX_RLE_SKIP);
00153         else
00154             skipcount = 0;
00155 
00156         total_skip_cost  = s->length_table[i + skipcount] + 2;
00157         s->skip_table[i] = skipcount;
00158 
00159 
00160         if (i < width - 1 && !memcmp(this_line, this_line + s->pixel_size, s->pixel_size))
00161             repeatcount = FFMIN(repeatcount + 1, MAX_RLE_REPEAT);
00162         else
00163             repeatcount = 1;
00164 
00165         total_repeat_cost = s->length_table[i + repeatcount] + 1 + s->pixel_size;
00166 
00167         
00168 
00169         if (i == 0) {
00170             total_skip_cost--;
00171             total_repeat_cost++;
00172         }
00173 
00174         if (repeatcount > 1 && (skipcount == 0 || total_repeat_cost < total_skip_cost)) {
00175             
00176             s->length_table[i]  = total_repeat_cost;
00177             s->rlecode_table[i] = -repeatcount;
00178         }
00179         else if (skipcount > 0) {
00180             
00181             s->length_table[i]  = total_skip_cost;
00182             s->rlecode_table[i] = 0;
00183         }
00184         else {
00185             
00186 
00187 
00188             int limit = FFMIN(width - i, MAX_RLE_BULK);
00189 
00190             temp_cost = 1 + s->pixel_size + !i;
00191             total_bulk_cost = INT_MAX;
00192 
00193             for (j = 1; j <= limit; j++) {
00194                 if (s->length_table[i + j] + temp_cost < total_bulk_cost) {
00195                     
00196                     total_bulk_cost = s->length_table[i + j] + temp_cost;
00197                     bulkcount = j;
00198                 }
00199                 temp_cost += s->pixel_size;
00200             }
00201 
00202             s->length_table[i]  = total_bulk_cost;
00203             s->rlecode_table[i] = bulkcount;
00204         }
00205 
00206         this_line -= s->pixel_size;
00207         prev_line -= s->pixel_size;
00208     }
00209 
00210     
00211 
00212     
00213 
00214 
00215     i=0;
00216     this_line = p->               data[0] + line*p->linesize[0];
00217 
00218     if (s->rlecode_table[0] == 0) {
00219         bytestream_put_byte(buf, s->skip_table[0] + 1);
00220         i += s->skip_table[0];
00221     }
00222     else bytestream_put_byte(buf, 1);
00223 
00224 
00225     while (i < width) {
00226         rlecode = s->rlecode_table[i];
00227         bytestream_put_byte(buf, rlecode);
00228         if (rlecode == 0) {
00229             
00230             bytestream_put_byte(buf, s->skip_table[i] + 1);
00231             i += s->skip_table[i];
00232         }
00233         else if (rlecode > 0) {
00234             
00235             if (s->avctx->pix_fmt == PIX_FMT_GRAY8) {
00236                 int j;
00237                 
00238                 
00239                 
00240                 for (j = 0; j < rlecode*s->pixel_size; ++j)
00241                     bytestream_put_byte(buf, *(this_line + i*s->pixel_size + j) ^ 0xff);
00242             } else {
00243                 bytestream_put_buffer(buf, this_line + i*s->pixel_size, rlecode*s->pixel_size);
00244             }
00245             i += rlecode;
00246         }
00247         else {
00248             
00249             if (s->avctx->pix_fmt == PIX_FMT_GRAY8) {
00250                 int j;
00251                 
00252                 for (j = 0; j < s->pixel_size; ++j)
00253                     bytestream_put_byte(buf, *(this_line + i*s->pixel_size + j) ^ 0xff);
00254             } else {
00255                 bytestream_put_buffer(buf, this_line + i*s->pixel_size, s->pixel_size);
00256             }
00257             i -= rlecode;
00258         }
00259     }
00260     bytestream_put_byte(buf, -1); 
00261 }
00262 
00264 static int encode_frame(QtrleEncContext *s, const AVFrame *p, uint8_t *buf)
00265 {
00266     int i;
00267     int start_line = 0;
00268     int end_line = s->avctx->height;
00269     uint8_t *orig_buf = buf;
00270 
00271     if (!s->frame.key_frame) {
00272         unsigned line_size = s->logical_width * s->pixel_size;
00273         for (start_line = 0; start_line < s->avctx->height; start_line++)
00274             if (memcmp(p->data[0] + start_line*p->linesize[0],
00275                        s->previous_frame.data[0] + start_line*s->previous_frame.linesize[0],
00276                        line_size))
00277                 break;
00278 
00279         for (end_line=s->avctx->height; end_line > start_line; end_line--)
00280             if (memcmp(p->data[0] + (end_line - 1)*p->linesize[0],
00281                        s->previous_frame.data[0] + (end_line - 1)*s->previous_frame.linesize[0],
00282                        line_size))
00283                 break;
00284     }
00285 
00286     bytestream_put_be32(&buf, 0);                         
00287 
00288     if ((start_line == 0 && end_line == s->avctx->height) || start_line == s->avctx->height)
00289         bytestream_put_be16(&buf, 0);                     
00290     else {
00291         bytestream_put_be16(&buf, 8);                     
00292         bytestream_put_be16(&buf, start_line);            
00293         bytestream_put_be16(&buf, 0);                     
00294         bytestream_put_be16(&buf, end_line - start_line); 
00295         bytestream_put_be16(&buf, 0);                     
00296     }
00297     for (i = start_line; i < end_line; i++)
00298         qtrle_encode_line(s, p, i, &buf);
00299 
00300     bytestream_put_byte(&buf, 0);                         
00301     AV_WB32(orig_buf, buf - orig_buf);                    
00302     return buf - orig_buf;
00303 }
00304 
00305 static int qtrle_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
00306                               const AVFrame *pict, int *got_packet)
00307 {
00308     QtrleEncContext * const s = avctx->priv_data;
00309     AVFrame * const p = &s->frame;
00310     int ret;
00311 
00312     *p = *pict;
00313 
00314     if ((ret = ff_alloc_packet2(avctx, pkt, s->max_buf_size)) < 0)
00315         return ret;
00316 
00317     if (avctx->gop_size == 0 || (s->avctx->frame_number % avctx->gop_size) == 0) {
00318         
00319         p->pict_type = AV_PICTURE_TYPE_I;
00320         p->key_frame = 1;
00321     } else {
00322         
00323         p->pict_type = AV_PICTURE_TYPE_P;
00324         p->key_frame = 0;
00325     }
00326 
00327     pkt->size = encode_frame(s, pict, pkt->data);
00328 
00329     
00330     av_picture_copy(&s->previous_frame, (AVPicture *)p, avctx->pix_fmt, avctx->width, avctx->height);
00331 
00332     if (p->key_frame)
00333         pkt->flags |= AV_PKT_FLAG_KEY;
00334     *got_packet = 1;
00335 
00336     return 0;
00337 }
00338 
00339 static av_cold int qtrle_encode_end(AVCodecContext *avctx)
00340 {
00341     QtrleEncContext *s = avctx->priv_data;
00342 
00343     avpicture_free(&s->previous_frame);
00344     av_free(s->rlecode_table);
00345     av_free(s->length_table);
00346     av_free(s->skip_table);
00347     return 0;
00348 }
00349 
00350 AVCodec ff_qtrle_encoder = {
00351     .name           = "qtrle",
00352     .type           = AVMEDIA_TYPE_VIDEO,
00353     .id             = AV_CODEC_ID_QTRLE,
00354     .priv_data_size = sizeof(QtrleEncContext),
00355     .init           = qtrle_encode_init,
00356     .encode2        = qtrle_encode_frame,
00357     .close          = qtrle_encode_end,
00358     .pix_fmts       = (const enum PixelFormat[]){
00359         PIX_FMT_RGB24, PIX_FMT_RGB555BE, PIX_FMT_ARGB, PIX_FMT_GRAY8, PIX_FMT_NONE
00360     },
00361     .long_name      = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"),
00362 };