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

libavcodec/flashsv2enc.c

Go to the documentation of this file.
00001 /*
00002  * Flash Screen Video Version 2 encoder
00003  * Copyright (C) 2009 Joshua Warner
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00028 /* Differences from version 1 stream:
00029  * NOTE: Currently, the only player that supports version 2 streams is Adobe Flash Player itself.
00030  * * Supports sending only a range of scanlines in a block,
00031  *   indicating a difference from the corresponding block in the last keyframe.
00032  * * Supports initializing the zlib dictionary with data from the corresponding
00033  *   block in the last keyframe, to improve compression.
00034  * * Supports a hybrid 15-bit rgb / 7-bit palette color space.
00035  */
00036 
00037 /* TODO:
00038  * Don't keep Block structures for both current frame and keyframe.
00039  * Make better heuristics for deciding stream parameters (optimum_* functions).  Currently these return constants.
00040  * Figure out how to encode palette information in the stream, choose an optimum palette at each keyframe.
00041  * Figure out how the zlibPrimeCompressCurrent flag works, implement support.
00042  * Find other sample files (that weren't generated here), develop a decoder.
00043  */
00044 
00045 #include <stdio.h>
00046 #include <stdlib.h>
00047 #include <zlib.h>
00048 
00049 #include "libavutil/imgutils.h"
00050 #include "avcodec.h"
00051 #include "put_bits.h"
00052 #include "bytestream.h"
00053 
00054 #define HAS_IFRAME_IMAGE 0x02
00055 #define HAS_PALLET_INFO 0x01
00056 
00057 #define COLORSPACE_BGR 0x00
00058 #define COLORSPACE_15_7 0x10
00059 #define HAS_DIFF_BLOCKS 0x04
00060 #define ZLIB_PRIME_COMPRESS_CURRENT 0x02
00061 #define ZLIB_PRIME_COMPRESS_PREVIOUS 0x01
00062 
00063 // Disables experimental "smart" parameter-choosing code, as well as the statistics that it depends on.
00064 // At the moment, the "smart" code is a great example of how the parameters *shouldn't* be chosen.
00065 #define FLASHSV2_DUMB
00066 
00067 typedef struct Block {
00068     uint8_t *enc;
00069     uint8_t *sl_begin, *sl_end;
00070     int enc_size;
00071     uint8_t *data;
00072     unsigned long data_size;
00073 
00074     uint8_t start, len;
00075     uint8_t dirty;
00076     uint8_t col, row, width, height;
00077     uint8_t flags;
00078 } Block;
00079 
00080 typedef struct Palette {
00081     unsigned colors[128];
00082     uint8_t index[1 << 15];
00083 } Palette;
00084 
00085 typedef struct FlashSV2Context {
00086     AVCodecContext *avctx;
00087     uint8_t *current_frame;
00088     uint8_t *key_frame;
00089     AVFrame frame;
00090     uint8_t *encbuffer;
00091     uint8_t *keybuffer;
00092     uint8_t *databuffer;
00093 
00094     Block *frame_blocks;
00095     Block *key_blocks;
00096     int frame_size;
00097     int blocks_size;
00098 
00099     int use15_7, dist, comp;
00100 
00101     int rows, cols;
00102 
00103     int last_key_frame;
00104 
00105     int image_width, image_height;
00106     int block_width, block_height;
00107     uint8_t flags;
00108     uint8_t use_custom_palette;
00109     uint8_t palette_type;       
00110     Palette palette;
00111 #ifndef FLASHSV2_DUMB
00112     double tot_blocks;          
00113     double diff_blocks;         
00114     double tot_lines;           
00115     double diff_lines;          
00116     double raw_size;            
00117     double comp_size;           
00118     double uncomp_size;         
00119 
00120     double total_bits;          
00121 #endif
00122 } FlashSV2Context;
00123 
00124 static av_cold void cleanup(FlashSV2Context * s)
00125 {
00126     av_freep(&s->encbuffer);
00127     av_freep(&s->keybuffer);
00128     av_freep(&s->databuffer);
00129     av_freep(&s->current_frame);
00130     av_freep(&s->key_frame);
00131 
00132     av_freep(&s->frame_blocks);
00133     av_freep(&s->key_blocks);
00134 }
00135 
00136 static void init_blocks(FlashSV2Context * s, Block * blocks,
00137                         uint8_t * encbuf, uint8_t * databuf)
00138 {
00139     int row, col;
00140     Block *b;
00141     for (col = 0; col < s->cols; col++) {
00142         for (row = 0; row < s->rows; row++) {
00143             b = blocks + (col + row * s->cols);
00144             b->width = (col < s->cols - 1) ?
00145                 s->block_width :
00146                 s->image_width - col * s->block_width;
00147 
00148             b->height = (row < s->rows - 1) ?
00149                 s->block_height :
00150                 s->image_height - row * s->block_height;
00151 
00152             b->row   = row;
00153             b->col   = col;
00154             b->enc   = encbuf;
00155             b->data  = databuf;
00156             encbuf  += b->width * b->height * 3;
00157             databuf += !databuf ? 0 : b->width * b->height * 6;
00158         }
00159     }
00160 }
00161 
00162 static void reset_stats(FlashSV2Context * s)
00163 {
00164 #ifndef FLASHSV2_DUMB
00165     s->diff_blocks = 0.1;
00166     s->tot_blocks = 1;
00167     s->diff_lines = 0.1;
00168     s->tot_lines = 1;
00169     s->raw_size = s->comp_size = s->uncomp_size = 10;
00170 #endif
00171 }
00172 
00173 static av_cold int flashsv2_encode_init(AVCodecContext * avctx)
00174 {
00175     FlashSV2Context *s = avctx->priv_data;
00176 
00177     s->avctx = avctx;
00178 
00179     s->comp = avctx->compression_level;
00180     if (s->comp == -1)
00181         s->comp = 9;
00182     if (s->comp < 0 || s->comp > 9) {
00183         av_log(avctx, AV_LOG_ERROR,
00184                "Compression level should be 0-9, not %d\n", s->comp);
00185         return -1;
00186     }
00187 
00188 
00189     if ((avctx->width > 4095) || (avctx->height > 4095)) {
00190         av_log(avctx, AV_LOG_ERROR,
00191                "Input dimensions too large, input must be max 4096x4096 !\n");
00192         return -1;
00193     }
00194 
00195     if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0)
00196         return -1;
00197 
00198 
00199     s->last_key_frame = 0;
00200 
00201     s->image_width  = avctx->width;
00202     s->image_height = avctx->height;
00203 
00204     s->block_width  = (s->image_width /  12) & ~15;
00205     s->block_height = (s->image_height / 12) & ~15;
00206 
00207     s->rows = (s->image_height + s->block_height - 1) / s->block_height;
00208     s->cols = (s->image_width +  s->block_width -  1) / s->block_width;
00209 
00210     s->frame_size  = s->image_width * s->image_height * 3;
00211     s->blocks_size = s->rows * s->cols * sizeof(Block);
00212 
00213     s->encbuffer     = av_mallocz(s->frame_size);
00214     s->keybuffer     = av_mallocz(s->frame_size);
00215     s->databuffer    = av_mallocz(s->frame_size * 6);
00216     s->current_frame = av_mallocz(s->frame_size);
00217     s->key_frame     = av_mallocz(s->frame_size);
00218     s->frame_blocks  = av_mallocz(s->blocks_size);
00219     s->key_blocks    = av_mallocz(s->blocks_size);
00220 
00221     init_blocks(s, s->frame_blocks, s->encbuffer, s->databuffer);
00222     init_blocks(s, s->key_blocks,   s->keybuffer, 0);
00223     reset_stats(s);
00224 #ifndef FLASHSV2_DUMB
00225     s->total_bits = 1;
00226 #endif
00227 
00228     s->use_custom_palette =  0;
00229     s->palette_type       = -1;        // so that the palette will be generated in reconfigure_at_keyframe
00230 
00231     if (!s->encbuffer || !s->keybuffer || !s->databuffer
00232         || !s->current_frame || !s->key_frame || !s->key_blocks
00233         || !s->frame_blocks) {
00234         av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
00235         cleanup(s);
00236         return -1;
00237     }
00238 
00239     return 0;
00240 }
00241 
00242 static int new_key_frame(FlashSV2Context * s)
00243 {
00244     int i;
00245     memcpy(s->key_blocks, s->frame_blocks, s->blocks_size);
00246     memcpy(s->key_frame, s->current_frame, s->frame_size);
00247 
00248     for (i = 0; i < s->rows * s->cols; i++) {
00249         s->key_blocks[i].enc += (s->keybuffer - s->encbuffer);
00250         s->key_blocks[i].sl_begin = 0;
00251         s->key_blocks[i].sl_end   = 0;
00252         s->key_blocks[i].data     = 0;
00253     }
00254     FFSWAP(uint8_t * , s->keybuffer, s->encbuffer);
00255 
00256     return 0;
00257 }
00258 
00259 static int write_palette(FlashSV2Context * s, uint8_t * buf, int buf_size)
00260 {
00261     //this isn't implemented yet!  Default palette only!
00262     return -1;
00263 }
00264 
00265 static int write_header(FlashSV2Context * s, uint8_t * buf, int buf_size)
00266 {
00267     PutBitContext pb;
00268     int buf_pos, len;
00269 
00270     if (buf_size < 5)
00271         return -1;
00272 
00273     init_put_bits(&pb, buf, buf_size * 8);
00274 
00275     put_bits(&pb, 4, (s->block_width  >> 4) - 1);
00276     put_bits(&pb, 12, s->image_width);
00277     put_bits(&pb, 4, (s->block_height >> 4) - 1);
00278     put_bits(&pb, 12, s->image_height);
00279 
00280     flush_put_bits(&pb);
00281     buf_pos = 4;
00282 
00283     buf[buf_pos++] = s->flags;
00284 
00285     if (s->flags & HAS_PALLET_INFO) {
00286         len = write_palette(s, buf + buf_pos, buf_size - buf_pos);
00287         if (len < 0)
00288             return -1;
00289         buf_pos += len;
00290     }
00291 
00292     return buf_pos;
00293 }
00294 
00295 static int write_block(Block * b, uint8_t * buf, int buf_size)
00296 {
00297     int buf_pos = 0;
00298     unsigned block_size = b->data_size;
00299 
00300     if (b->flags & HAS_DIFF_BLOCKS)
00301         block_size += 2;
00302     if (b->flags & ZLIB_PRIME_COMPRESS_CURRENT)
00303         block_size += 2;
00304     if (block_size > 0)
00305         block_size += 1;
00306     if (buf_size < block_size + 2)
00307         return -1;
00308 
00309     buf[buf_pos++] = block_size >> 8;
00310     buf[buf_pos++] = block_size;
00311 
00312     if (block_size == 0)
00313         return buf_pos;
00314 
00315     buf[buf_pos++] = b->flags;
00316 
00317     if (b->flags & HAS_DIFF_BLOCKS) {
00318         buf[buf_pos++] = (b->start);
00319         buf[buf_pos++] = (b->len);
00320     }
00321 
00322     if (b->flags & ZLIB_PRIME_COMPRESS_CURRENT) {
00323         //This feature of the format is poorly understood, and as of now, unused.
00324         buf[buf_pos++] = (b->col);
00325         buf[buf_pos++] = (b->row);
00326     }
00327 
00328     memcpy(buf + buf_pos, b->data, b->data_size);
00329 
00330     buf_pos += b->data_size;
00331 
00332     return buf_pos;
00333 }
00334 
00335 static int encode_zlib(Block * b, uint8_t * buf, unsigned long *buf_size, int comp)
00336 {
00337     int res = compress2(buf, buf_size, b->sl_begin, b->sl_end - b->sl_begin, comp);
00338     return res == Z_OK ? 0 : -1;
00339 }
00340 
00341 static int encode_zlibprime(Block * b, Block * prime, uint8_t * buf,
00342                             int *buf_size, int comp)
00343 {
00344     z_stream s;
00345     int res;
00346     s.zalloc = NULL;
00347     s.zfree  = NULL;
00348     s.opaque = NULL;
00349     res = deflateInit(&s, comp);
00350     if (res < 0)
00351         return -1;
00352 
00353     s.next_in  = prime->enc;
00354     s.avail_in = prime->enc_size;
00355     while (s.avail_in > 0) {
00356         s.next_out  = buf;
00357         s.avail_out = *buf_size;
00358         res = deflate(&s, Z_SYNC_FLUSH);
00359         if (res < 0)
00360             return -1;
00361     }
00362 
00363     s.next_in   = b->sl_begin;
00364     s.avail_in  = b->sl_end - b->sl_begin;
00365     s.next_out  = buf;
00366     s.avail_out = *buf_size;
00367     res = deflate(&s, Z_FINISH);
00368     deflateEnd(&s);
00369     *buf_size -= s.avail_out;
00370     if (res != Z_STREAM_END)
00371         return -1;
00372     return 0;
00373 }
00374 
00375 static int encode_bgr(Block * b, const uint8_t * src, int stride)
00376 {
00377     int i;
00378     uint8_t *ptr = b->enc;
00379     for (i = 0; i < b->start; i++)
00380         memcpy(ptr + i * b->width * 3, src + i * stride, b->width * 3);
00381     b->sl_begin = ptr + i * b->width * 3;
00382     for (; i < b->start + b->len; i++)
00383         memcpy(ptr + i * b->width * 3, src + i * stride, b->width * 3);
00384     b->sl_end = ptr + i * b->width * 3;
00385     for (; i < b->height; i++)
00386         memcpy(ptr + i * b->width * 3, src + i * stride, b->width * 3);
00387     b->enc_size = ptr + i * b->width * 3 - b->enc;
00388     return b->enc_size;
00389 }
00390 
00391 static inline unsigned pixel_color15(const uint8_t * src)
00392 {
00393     return (src[0] >> 3) | ((src[1] & 0xf8) << 2) | ((src[2] & 0xf8) << 7);
00394 }
00395 
00396 static inline unsigned int chroma_diff(unsigned int c1, unsigned int c2)
00397 {
00398     unsigned int t1 = (c1 & 0x000000ff) + ((c1 & 0x0000ff00) >> 8) + ((c1 & 0x00ff0000) >> 16);
00399     unsigned int t2 = (c2 & 0x000000ff) + ((c2 & 0x0000ff00) >> 8) + ((c2 & 0x00ff0000) >> 16);
00400 
00401     return abs(t1 - t2) + abs((c1 & 0x000000ff) - (c2 & 0x000000ff)) +
00402         abs(((c1 & 0x0000ff00) >> 8) - ((c2 & 0x0000ff00) >> 8)) +
00403         abs(((c1 & 0x00ff0000) >> 16) - ((c2 & 0x00ff0000) >> 16));
00404 }
00405 
00406 static inline int pixel_color7_fast(Palette * palette, unsigned c15)
00407 {
00408     return palette->index[c15];
00409 }
00410 
00411 static int pixel_color7_slow(Palette * palette, unsigned color)
00412 {
00413     int i, min = 0x7fffffff;
00414     int minc = -1;
00415     for (i = 0; i < 128; i++) {
00416         int c1 = palette->colors[i];
00417         int diff = chroma_diff(c1, color);
00418         if (diff < min) {
00419             min = diff;
00420             minc = i;
00421         }
00422     }
00423     return minc;
00424 }
00425 
00426 static inline unsigned pixel_bgr(const uint8_t * src)
00427 {
00428     return (src[0]) | (src[1] << 8) | (src[2] << 16);
00429 }
00430 
00431 static int write_pixel_15_7(Palette * palette, uint8_t * dest, const uint8_t * src,
00432                             int dist)
00433 {
00434     unsigned c15 = pixel_color15(src);
00435     unsigned color = pixel_bgr(src);
00436     int d15 = chroma_diff(color, color & 0x00f8f8f8);
00437     int c7 = pixel_color7_fast(palette, c15);
00438     int d7 = chroma_diff(color, palette->colors[c7]);
00439     if (dist + d15 >= d7) {
00440         dest[0] = c7;
00441         return 1;
00442     } else {
00443         dest[0] = 0x80 | (c15 >> 8);
00444         dest[1] = c15 & 0xff;
00445         return 2;
00446     }
00447 }
00448 
00449 static int update_palette_index(Palette * palette)
00450 {
00451     int r, g, b;
00452     unsigned int bgr, c15, index;
00453     for (r = 4; r < 256; r += 8) {
00454         for (g = 4; g < 256; g += 8) {
00455             for (b = 4; b < 256; b += 8) {
00456                 bgr = b | (g << 8) | (r << 16);
00457                 c15 = (b >> 3) | ((g & 0xf8) << 2) | ((r & 0xf8) << 7);
00458                 index = pixel_color7_slow(palette, bgr);
00459 
00460                 palette->index[c15] = index;
00461             }
00462         }
00463     }
00464     return 0;
00465 }
00466 
00467 static const unsigned int default_screen_video_v2_palette[128] = {
00468     0x00000000, 0x00333333, 0x00666666, 0x00999999, 0x00CCCCCC, 0x00FFFFFF,
00469     0x00330000, 0x00660000, 0x00990000, 0x00CC0000, 0x00FF0000, 0x00003300,
00470     0x00006600, 0x00009900, 0x0000CC00, 0x0000FF00, 0x00000033, 0x00000066,
00471     0x00000099, 0x000000CC, 0x000000FF, 0x00333300, 0x00666600, 0x00999900,
00472     0x00CCCC00, 0x00FFFF00, 0x00003333, 0x00006666, 0x00009999, 0x0000CCCC,
00473     0x0000FFFF, 0x00330033, 0x00660066, 0x00990099, 0x00CC00CC, 0x00FF00FF,
00474     0x00FFFF33, 0x00FFFF66, 0x00FFFF99, 0x00FFFFCC, 0x00FF33FF, 0x00FF66FF,
00475     0x00FF99FF, 0x00FFCCFF, 0x0033FFFF, 0x0066FFFF, 0x0099FFFF, 0x00CCFFFF,
00476     0x00CCCC33, 0x00CCCC66, 0x00CCCC99, 0x00CCCCFF, 0x00CC33CC, 0x00CC66CC,
00477     0x00CC99CC, 0x00CCFFCC, 0x0033CCCC, 0x0066CCCC, 0x0099CCCC, 0x00FFCCCC,
00478     0x00999933, 0x00999966, 0x009999CC, 0x009999FF, 0x00993399, 0x00996699,
00479     0x0099CC99, 0x0099FF99, 0x00339999, 0x00669999, 0x00CC9999, 0x00FF9999,
00480     0x00666633, 0x00666699, 0x006666CC, 0x006666FF, 0x00663366, 0x00669966,
00481     0x0066CC66, 0x0066FF66, 0x00336666, 0x00996666, 0x00CC6666, 0x00FF6666,
00482     0x00333366, 0x00333399, 0x003333CC, 0x003333FF, 0x00336633, 0x00339933,
00483     0x0033CC33, 0x0033FF33, 0x00663333, 0x00993333, 0x00CC3333, 0x00FF3333,
00484     0x00003366, 0x00336600, 0x00660033, 0x00006633, 0x00330066, 0x00663300,
00485     0x00336699, 0x00669933, 0x00993366, 0x00339966, 0x00663399, 0x00996633,
00486     0x006699CC, 0x0099CC66, 0x00CC6699, 0x0066CC99, 0x009966CC, 0x00CC9966,
00487     0x0099CCFF, 0x00CCFF99, 0x00FF99CC, 0x0099FFCC, 0x00CC99FF, 0x00FFCC99,
00488     0x00111111, 0x00222222, 0x00444444, 0x00555555, 0x00AAAAAA, 0x00BBBBBB,
00489     0x00DDDDDD, 0x00EEEEEE
00490 };
00491 
00492 static int generate_default_palette(Palette * palette)
00493 {
00494     memcpy(palette->colors, default_screen_video_v2_palette,
00495            sizeof(default_screen_video_v2_palette));
00496 
00497     return update_palette_index(palette);
00498 }
00499 
00500 static int generate_optimum_palette(Palette * palette, const uint8_t * image,
00501                                    int width, int height, int stride)
00502 {
00503     //this isn't implemented yet!  Default palette only!
00504     return -1;
00505 }
00506 
00507 static inline int encode_15_7_sl(Palette * palette, uint8_t * dest,
00508                                  const uint8_t * src, int width, int dist)
00509 {
00510     int len = 0, x;
00511     for (x = 0; x < width; x++) {
00512         len += write_pixel_15_7(palette, dest + len, src + 3 * x, dist);
00513     }
00514     return len;
00515 }
00516 
00517 static int encode_15_7(Palette * palette, Block * b, const uint8_t * src,
00518                        int stride, int dist)
00519 {
00520     int i;
00521     uint8_t *ptr = b->enc;
00522     for (i = 0; i < b->start; i++)
00523         ptr += encode_15_7_sl(palette, ptr, src + i * stride, b->width, dist);
00524     b->sl_begin = ptr;
00525     for (; i < b->start + b->len; i++)
00526         ptr += encode_15_7_sl(palette, ptr, src + i * stride, b->width, dist);
00527     b->sl_end = ptr;
00528     for (; i < b->height; i++)
00529         ptr += encode_15_7_sl(palette, ptr, src + i * stride, b->width, dist);
00530     b->enc_size = ptr - b->enc;
00531     return b->enc_size;
00532 }
00533 
00534 static int encode_block(Palette * palette, Block * b, Block * prev,
00535                         const uint8_t * src, int stride, int comp, int dist,
00536                         int keyframe)
00537 {
00538     unsigned buf_size = b->width * b->height * 6;
00539     uint8_t buf[buf_size];
00540     int res;
00541     if (b->flags & COLORSPACE_15_7) {
00542         encode_15_7(palette, b, src, stride, dist);
00543     } else {
00544         encode_bgr(b, src, stride);
00545     }
00546 
00547     if (b->len > 0) {
00548         b->data_size = buf_size;
00549         res = encode_zlib(b, b->data, &b->data_size, comp);
00550         if (res)
00551             return res;
00552 
00553         if (!keyframe) {
00554             res = encode_zlibprime(b, prev, buf, &buf_size, comp);
00555             if (res)
00556                 return res;
00557 
00558             if (buf_size < b->data_size) {
00559                 b->data_size = buf_size;
00560                 memcpy(b->data, buf, buf_size);
00561                 b->flags |= ZLIB_PRIME_COMPRESS_PREVIOUS;
00562             }
00563         }
00564     } else {
00565         b->data_size = 0;
00566     }
00567     return 0;
00568 }
00569 
00570 static int compare_sl(FlashSV2Context * s, Block * b, const uint8_t * src,
00571                       uint8_t * frame, uint8_t * key, int y, int keyframe)
00572 {
00573     if (memcmp(src, frame, b->width * 3) != 0) {
00574         b->dirty = 1;
00575         memcpy(frame, src, b->width * 3);
00576 #ifndef FLASHSV2_DUMB
00577         s->diff_lines++;
00578 #endif
00579     }
00580     if (memcmp(src, key, b->width * 3) != 0) {
00581         if (b->len == 0)
00582             b->start = y;
00583         b->len = y + 1 - b->start;
00584     }
00585     return 0;
00586 }
00587 
00588 static int mark_all_blocks(FlashSV2Context * s, const uint8_t * src, int stride,
00589                            int keyframe)
00590 {
00591     int sl, rsl, col, pos, possl;
00592     Block *b;
00593     for (sl = s->image_height - 1; sl >= 0; sl--) {
00594         for (col = 0; col < s->cols; col++) {
00595             rsl = s->image_height - sl - 1;
00596             b = s->frame_blocks + col + rsl / s->block_height * s->cols;
00597             possl = stride * sl + col * s->block_width * 3;
00598             pos = s->image_width * rsl * 3 + col * s->block_width * 3;
00599             compare_sl(s, b, src + possl, s->current_frame + pos,
00600                        s->key_frame + pos, rsl % s->block_height, keyframe);
00601         }
00602     }
00603 #ifndef FLASHSV2_DUMB
00604     s->tot_lines += s->image_height * s->cols;
00605 #endif
00606     return 0;
00607 }
00608 
00609 static int encode_all_blocks(FlashSV2Context * s, int keyframe)
00610 {
00611     int row, col, res;
00612     uint8_t *data;
00613     Block *b, *prev;
00614     for (row = 0; row < s->rows; row++) {
00615         for (col = 0; col < s->cols; col++) {
00616             b = s->frame_blocks + (row * s->cols + col);
00617             prev = s->key_blocks + (row * s->cols + col);
00618             if (keyframe) {
00619                 b->start = 0;
00620                 b->len = b->height;
00621                 b->flags = s->use15_7 ? COLORSPACE_15_7 : 0;
00622             } else if (!b->dirty) {
00623                 b->start = 0;
00624                 b->len = 0;
00625                 b->data_size = 0;
00626                 b->flags = s->use15_7 ? COLORSPACE_15_7 : 0;
00627                 continue;
00628             } else {
00629                 b->flags = s->use15_7 ? COLORSPACE_15_7 | HAS_DIFF_BLOCKS : HAS_DIFF_BLOCKS;
00630             }
00631             data = s->current_frame + s->image_width * 3 * s->block_height * row + s->block_width * col * 3;
00632             res = encode_block(&s->palette, b, prev, data, s->image_width * 3, s->comp, s->dist, keyframe);
00633 #ifndef FLASHSV2_DUMB
00634             if (b->dirty)
00635                 s->diff_blocks++;
00636             s->comp_size += b->data_size;
00637             s->uncomp_size += b->enc_size;
00638 #endif
00639             if (res)
00640                 return res;
00641         }
00642     }
00643 #ifndef FLASHSV2_DUMB
00644     s->raw_size += s->image_width * s->image_height * 3;
00645     s->tot_blocks += s->rows * s->cols;
00646 #endif
00647     return 0;
00648 }
00649 
00650 static int write_all_blocks(FlashSV2Context * s, uint8_t * buf,
00651                             int buf_size)
00652 {
00653     int row, col, buf_pos = 0, len;
00654     Block *b;
00655     for (row = 0; row < s->rows; row++) {
00656         for (col = 0; col < s->cols; col++) {
00657             b = s->frame_blocks + row * s->cols + col;
00658             len = write_block(b, buf + buf_pos, buf_size - buf_pos);
00659             b->start = b->len = b->dirty = 0;
00660             if (len < 0)
00661                 return len;
00662             buf_pos += len;
00663         }
00664     }
00665     return buf_pos;
00666 }
00667 
00668 static int write_bitstream(FlashSV2Context * s, const uint8_t * src, int stride,
00669                            uint8_t * buf, int buf_size, int keyframe)
00670 {
00671     int buf_pos, res;
00672 
00673     res = mark_all_blocks(s, src, stride, keyframe);
00674     if (res)
00675         return res;
00676     res = encode_all_blocks(s, keyframe);
00677     if (res)
00678         return res;
00679 
00680     res = write_header(s, buf, buf_size);
00681     if (res < 0) {
00682         return res;
00683     } else {
00684         buf_pos = res;
00685     }
00686     res = write_all_blocks(s, buf + buf_pos, buf_size - buf_pos);
00687     if (res < 0)
00688         return res;
00689     buf_pos += res;
00690 #ifndef FLASHSV2_DUMB
00691     s->total_bits += ((double) buf_pos) * 8.0;
00692 #endif
00693 
00694     return buf_pos;
00695 }
00696 
00697 static void recommend_keyframe(FlashSV2Context * s, int *keyframe)
00698 {
00699 #ifndef FLASHSV2_DUMB
00700     double block_ratio, line_ratio, enc_ratio, comp_ratio, data_ratio;
00701     if (s->avctx->gop_size > 0) {
00702         block_ratio = s->diff_blocks / s->tot_blocks;
00703         line_ratio = s->diff_lines / s->tot_lines;
00704         enc_ratio = s->uncomp_size / s->raw_size;
00705         comp_ratio = s->comp_size / s->uncomp_size;
00706         data_ratio = s->comp_size / s->raw_size;
00707 
00708         if ((block_ratio >= 0.5 && line_ratio / block_ratio <= 0.5) || line_ratio >= 0.95) {
00709             *keyframe = 1;
00710             return;
00711         }
00712     }
00713 #else
00714     return;
00715 #endif
00716 }
00717 
00718 static const double block_size_fraction = 1.0 / 300;
00719 static int optimum_block_width(FlashSV2Context * s)
00720 {
00721 #ifndef FLASHSV2_DUMB
00722     double save = (1-pow(s->diff_lines/s->diff_blocks/s->block_height, 0.5)) * s->comp_size/s->tot_blocks;
00723     double width = block_size_fraction * sqrt(0.5 * save * s->rows * s->cols) * s->image_width;
00724     int pwidth = ((int) width);
00725     return FFCLIP(pwidth & ~15, 256, 16);
00726 #else
00727     return 64;
00728 #endif
00729 }
00730 
00731 static int optimum_block_height(FlashSV2Context * s)
00732 {
00733 #ifndef FLASHSV2_DUMB
00734     double save = (1-pow(s->diff_lines/s->diff_blocks/s->block_height, 0.5)) * s->comp_size/s->tot_blocks;
00735     double height = block_size_fraction * sqrt(0.5 * save * s->rows * s->cols) * s->image_height;
00736     int pheight = ((int) height);
00737     return FFCLIP(pheight & ~15, 256, 16);
00738 #else
00739     return 64;
00740 #endif
00741 }
00742 
00743 static const double use15_7_threshold = 8192;
00744 
00745 static int optimum_use15_7(FlashSV2Context * s)
00746 {
00747 #ifndef FLASHSV2_DUMB
00748     double ideal = ((double)(s->avctx->bit_rate * s->avctx->time_base.den * s->avctx->ticks_per_frame)) /
00749         ((double) s->avctx->time_base.num) * s->avctx->frame_number;
00750     if (ideal + use15_7_threshold < s->total_bits) {
00751         return 1;
00752     } else {
00753         return 0;
00754     }
00755 #else
00756     return s->avctx->global_quality == 0;
00757 #endif
00758 }
00759 
00760 static const double color15_7_factor = 100;
00761 
00762 static int optimum_dist(FlashSV2Context * s)
00763 {
00764 #ifndef FLASHSV2_DUMB
00765     double ideal =
00766         s->avctx->bit_rate * s->avctx->time_base.den *
00767         s->avctx->ticks_per_frame;
00768     int dist = pow((s->total_bits / ideal) * color15_7_factor, 3);
00769     av_log(s->avctx, AV_LOG_DEBUG, "dist: %d\n", dist);
00770     return dist;
00771 #else
00772     return 15;
00773 #endif
00774 }
00775 
00776 
00777 static int reconfigure_at_keyframe(FlashSV2Context * s, const uint8_t * image,
00778                                    int stride)
00779 {
00780     int update_palette = 0;
00781     int res;
00782     s->block_width = optimum_block_width(s);
00783     s->block_height = optimum_block_height(s);
00784 
00785     s->rows = (s->image_height + s->block_height - 1) / s->block_height;
00786     s->cols = (s->image_width +  s->block_width -  1) / s->block_width;
00787 
00788     if (s->rows * s->cols != s->blocks_size / sizeof(Block)) {
00789         if (s->rows * s->cols > s->blocks_size / sizeof(Block)) {
00790             s->frame_blocks = av_realloc(s->frame_blocks, s->rows * s->cols * sizeof(Block));
00791             s->key_blocks = av_realloc(s->key_blocks, s->cols * s->rows * sizeof(Block));
00792             if (!s->frame_blocks || !s->key_blocks) {
00793                 av_log(s->avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
00794                 return -1;
00795             }
00796             s->blocks_size = s->rows * s->cols * sizeof(Block);
00797         }
00798         init_blocks(s, s->frame_blocks, s->encbuffer, s->databuffer);
00799         init_blocks(s, s->key_blocks, s->keybuffer, 0);
00800 
00801     }
00802 
00803     s->use15_7 = optimum_use15_7(s);
00804     if (s->use15_7) {
00805         if ((s->use_custom_palette && s->palette_type != 1) || update_palette) {
00806             res = generate_optimum_palette(&s->palette, image, s->image_width, s->image_height, stride);
00807             if (res)
00808                 return res;
00809             s->palette_type = 1;
00810             av_log(s->avctx, AV_LOG_DEBUG, "Generated optimum palette\n");
00811         } else if (!s->use_custom_palette && s->palette_type != 0) {
00812             res = generate_default_palette(&s->palette);
00813             if (res)
00814                 return res;
00815             s->palette_type = 0;
00816             av_log(s->avctx, AV_LOG_DEBUG, "Generated default palette\n");
00817         }
00818     }
00819 
00820 
00821     reset_stats(s);
00822 
00823     return 0;
00824 }
00825 
00826 static int flashsv2_encode_frame(AVCodecContext * avctx, uint8_t * buf,
00827                                  int buf_size, void *data)
00828 {
00829     FlashSV2Context *const s = avctx->priv_data;
00830     AVFrame *pict = data;
00831     AVFrame *const p = &s->frame;
00832     int res;
00833     int keyframe = 0;
00834 
00835     *p = *pict;
00836 
00837     /* First frame needs to be a keyframe */
00838     if (avctx->frame_number == 0)
00839         keyframe = 1;
00840 
00841     /* Check the placement of keyframes */
00842     if (avctx->gop_size > 0) {
00843         if (avctx->frame_number >= s->last_key_frame + avctx->gop_size)
00844             keyframe = 1;
00845     }
00846 
00847     if (buf_size < s->frame_size) {
00848         //Conservative upper bound check for compressed data
00849         av_log(avctx, AV_LOG_ERROR, "buf_size %d <  %d\n", buf_size, s->frame_size);
00850         return -1;
00851     }
00852 
00853     if (!keyframe
00854         && avctx->frame_number > s->last_key_frame + avctx->keyint_min) {
00855         recommend_keyframe(s, &keyframe);
00856         if (keyframe)
00857             av_log(avctx, AV_LOG_DEBUG, "Recommending key frame at frame %d\n", avctx->frame_number);
00858     }
00859 
00860     if (keyframe) {
00861         res = reconfigure_at_keyframe(s, p->data[0], p->linesize[0]);
00862         if (res)
00863             return res;
00864     }
00865 
00866     if (s->use15_7)
00867         s->dist = optimum_dist(s);
00868 
00869     res = write_bitstream(s, p->data[0], p->linesize[0], buf, buf_size, keyframe);
00870 
00871     if (keyframe) {
00872         new_key_frame(s);
00873         p->pict_type = FF_I_TYPE;
00874         p->key_frame = 1;
00875         s->last_key_frame = avctx->frame_number;
00876         av_log(avctx, AV_LOG_DEBUG, "Inserting key frame at frame %d\n", avctx->frame_number);
00877     } else {
00878         p->pict_type = FF_P_TYPE;
00879         p->key_frame = 0;
00880     }
00881 
00882     avctx->coded_frame = p;
00883 
00884     return res;
00885 }
00886 
00887 static av_cold int flashsv2_encode_end(AVCodecContext * avctx)
00888 {
00889     FlashSV2Context *s = avctx->priv_data;
00890 
00891     cleanup(s);
00892 
00893     return 0;
00894 }
00895 
00896 AVCodec ff_flashsv2_encoder = {
00897     "flashsv2",
00898     AVMEDIA_TYPE_VIDEO,
00899     CODEC_ID_FLASHSV2,
00900     sizeof(FlashSV2Context),
00901     flashsv2_encode_init,
00902     flashsv2_encode_frame,
00903     flashsv2_encode_end,
00904     .pix_fmts = (enum PixelFormat[]) {PIX_FMT_BGR24, PIX_FMT_NONE},
00905     .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video Version 2"),
00906     .capabilities   =  CODEC_CAP_EXPERIMENTAL,
00907 };

Generated on Wed Apr 11 2012 07:31:33 for FFmpeg by  doxygen 1.7.1