libspeex: allow custom sample rates again.
[ffmpeg.git] / libavcodec / flashsv2enc.c
index 44c9bc6..1d0d196 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /**
- * @file libavcodec/flashsv2enc.c
+ * @file
  * Flash Screen Video Version 2 encoder
  * @author Joshua Warner
  */
@@ -48,6 +48,7 @@
 
 #include "libavutil/imgutils.h"
 #include "avcodec.h"
+#include "internal.h"
 #include "put_bits.h"
 #include "bytestream.h"
 
@@ -91,6 +92,9 @@ typedef struct FlashSV2Context {
     uint8_t *keybuffer;
     uint8_t *databuffer;
 
+    uint8_t *blockbuffer;
+    int blockbuffer_size;
+
     Block *frame_blocks;
     Block *key_blocks;
     int frame_size;
@@ -123,14 +127,15 @@ typedef struct FlashSV2Context {
 
 static av_cold void cleanup(FlashSV2Context * s)
 {
-        av_free(s->encbuffer);
-        av_free(s->keybuffer);
-        av_free(s->databuffer);
-        av_free(s->current_frame);
-        av_free(s->key_frame);
+    av_freep(&s->encbuffer);
+    av_freep(&s->keybuffer);
+    av_freep(&s->databuffer);
+    av_freep(&s->blockbuffer);
+    av_freep(&s->current_frame);
+    av_freep(&s->key_frame);
 
-        av_free(s->frame_blocks);
-        av_free(s->key_blocks);
+    av_freep(&s->frame_blocks);
+    av_freep(&s->key_blocks);
 }
 
 static void init_blocks(FlashSV2Context * s, Block * blocks,
@@ -191,6 +196,11 @@ static av_cold int flashsv2_encode_init(AVCodecContext * avctx)
                "Input dimensions too large, input must be max 4096x4096 !\n");
         return -1;
     }
+    if ((avctx->width < 16) || (avctx->height < 16)) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Input dimensions too small, input must be at least 16x16 !\n");
+        return -1;
+    }
 
     if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0)
         return -1;
@@ -204,6 +214,11 @@ static av_cold int flashsv2_encode_init(AVCodecContext * avctx)
     s->block_width  = (s->image_width /  12) & ~15;
     s->block_height = (s->image_height / 12) & ~15;
 
+    if(!s->block_width)
+        s->block_width = 1;
+    if(!s->block_height)
+        s->block_height = 1;
+
     s->rows = (s->image_height + s->block_height - 1) / s->block_height;
     s->cols = (s->image_width +  s->block_width -  1) / s->block_width;
 
@@ -218,6 +233,9 @@ static av_cold int flashsv2_encode_init(AVCodecContext * avctx)
     s->frame_blocks  = av_mallocz(s->blocks_size);
     s->key_blocks    = av_mallocz(s->blocks_size);
 
+    s->blockbuffer      = NULL;
+    s->blockbuffer_size = 0;
+
     init_blocks(s, s->frame_blocks, s->encbuffer, s->databuffer);
     init_blocks(s, s->key_blocks,   s->keybuffer, 0);
     reset_stats(s);
@@ -242,7 +260,6 @@ static av_cold int flashsv2_encode_init(AVCodecContext * avctx)
 static int new_key_frame(FlashSV2Context * s)
 {
     int i;
-    FFSWAP(uint8_t * , s->keybuffer, s->encbuffer);
     memcpy(s->key_blocks, s->frame_blocks, s->blocks_size);
     memcpy(s->key_frame, s->current_frame, s->frame_size);
 
@@ -252,6 +269,7 @@ static int new_key_frame(FlashSV2Context * s)
         s->key_blocks[i].sl_end   = 0;
         s->key_blocks[i].data     = 0;
     }
+    memcpy(s->keybuffer, s->encbuffer, s->frame_size);
 
     return 0;
 }
@@ -315,14 +333,14 @@ static int write_block(Block * b, uint8_t * buf, int buf_size)
     buf[buf_pos++] = b->flags;
 
     if (b->flags & HAS_DIFF_BLOCKS) {
-        buf[buf_pos++] = (uint8_t) (b->start);
-        buf[buf_pos++] = (uint8_t) (b->len);
+        buf[buf_pos++] = (b->start);
+        buf[buf_pos++] = (b->len);
     }
 
     if (b->flags & ZLIB_PRIME_COMPRESS_CURRENT) {
         //This feature of the format is poorly understood, and as of now, unused.
-        buf[buf_pos++] = (uint8_t) (b->col);
-        buf[buf_pos++] = (uint8_t) (b->row);
+        buf[buf_pos++] = (b->col);
+        buf[buf_pos++] = (b->row);
     }
 
     memcpy(buf + buf_pos, b->data, b->data_size);
@@ -437,10 +455,10 @@ static int write_pixel_15_7(Palette * palette, uint8_t * dest, const uint8_t * s
     int c7 = pixel_color7_fast(palette, c15);
     int d7 = chroma_diff(color, palette->colors[c7]);
     if (dist + d15 >= d7) {
-        dest[0] = (uint8_t) c7;
+        dest[0] = c7;
         return 1;
     } else {
-        dest[0] = 0x80 | (uint8_t) (c15 >> 8);
+        dest[0] = 0x80 | (c15 >> 8);
         dest[1] = c15 & 0xff;
         return 2;
     }
@@ -531,13 +549,14 @@ static int encode_15_7(Palette * palette, Block * b, const uint8_t * src,
     return b->enc_size;
 }
 
-static int encode_block(Palette * palette, Block * b, Block * prev,
-                        const uint8_t * src, int stride, int comp, int dist,
-                        int keyframe)
+static int encode_block(FlashSV2Context *s, Palette * palette, Block * b,
+                        Block * prev, const uint8_t * src, int stride, int comp,
+                        int dist, int keyframe)
 {
     unsigned buf_size = b->width * b->height * 6;
-    uint8_t buf[buf_size];
+    uint8_t *buf = s->blockbuffer;
     int res;
+
     if (b->flags & COLORSPACE_15_7) {
         encode_15_7(palette, b, src, stride, dist);
     } else {
@@ -615,21 +634,20 @@ static int encode_all_blocks(FlashSV2Context * s, int keyframe)
         for (col = 0; col < s->cols; col++) {
             b = s->frame_blocks + (row * s->cols + col);
             prev = s->key_blocks + (row * s->cols + col);
+            b->flags = s->use15_7 ? COLORSPACE_15_7 : 0;
             if (keyframe) {
                 b->start = 0;
                 b->len = b->height;
-                b->flags = s->use15_7 ? COLORSPACE_15_7 : 0;
             } else if (!b->dirty) {
                 b->start = 0;
                 b->len = 0;
                 b->data_size = 0;
-                b->flags = s->use15_7 ? COLORSPACE_15_7 : 0;
                 continue;
-            } else {
-                b->flags = s->use15_7 ? COLORSPACE_15_7 | HAS_DIFF_BLOCKS : HAS_DIFF_BLOCKS;
+            } else if (b->start != 0 || b->len != b->height) {
+                b->flags |= HAS_DIFF_BLOCKS;
             }
             data = s->current_frame + s->image_width * 3 * s->block_height * row + s->block_width * col * 3;
-            res = encode_block(&s->palette, b, prev, data, s->image_width * 3, s->comp, s->dist, keyframe);
+            res = encode_block(s, &s->palette, b, prev, data, s->image_width * 3, s->comp, s->dist, keyframe);
 #ifndef FLASHSV2_DUMB
             if (b->dirty)
                 s->diff_blocks++;
@@ -779,13 +797,15 @@ static int reconfigure_at_keyframe(FlashSV2Context * s, const uint8_t * image,
 {
     int update_palette = 0;
     int res;
-    s->block_width = optimum_block_width(s);
-    s->block_height = optimum_block_height(s);
+    int block_width  = optimum_block_width (s);
+    int block_height = optimum_block_height(s);
 
-    s->rows = (s->image_height + s->block_height - 1) / s->block_height;
-    s->cols = (s->image_width +  s->block_width -  1) / s->block_width;
+    s->rows = (s->image_height + block_height - 1) / block_height;
+    s->cols = (s->image_width  + block_width  - 1) / block_width;
 
-    if (s->rows * s->cols != s->blocks_size / sizeof(Block)) {
+    if (block_width != s->block_width || block_height != s->block_height) {
+        s->block_width  = block_width;
+        s->block_height = block_height;
         if (s->rows * s->cols > s->blocks_size / sizeof(Block)) {
             s->frame_blocks = av_realloc(s->frame_blocks, s->rows * s->cols * sizeof(Block));
             s->key_blocks = av_realloc(s->key_blocks, s->cols * s->rows * sizeof(Block));
@@ -798,6 +818,11 @@ static int reconfigure_at_keyframe(FlashSV2Context * s, const uint8_t * image,
         init_blocks(s, s->frame_blocks, s->encbuffer, s->databuffer);
         init_blocks(s, s->key_blocks, s->keybuffer, 0);
 
+        av_fast_malloc(&s->blockbuffer, &s->blockbuffer_size, block_width * block_height * 6);
+        if (!s->blockbuffer) {
+            av_log(s->avctx, AV_LOG_ERROR, "Could not allocate block buffer.\n");
+            return AVERROR(ENOMEM);
+        }
     }
 
     s->use15_7 = optimum_use15_7(s);
@@ -823,17 +848,19 @@ static int reconfigure_at_keyframe(FlashSV2Context * s, const uint8_t * image,
     return 0;
 }
 
-static int flashsv2_encode_frame(AVCodecContext * avctx, uint8_t * buf,
-                                 int buf_size, void *data)
+static int flashsv2_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+                                 const AVFrame *pict, int *got_packet)
 {
     FlashSV2Context *const s = avctx->priv_data;
-    AVFrame *pict = data;
     AVFrame *const p = &s->frame;
     int res;
     int keyframe = 0;
 
     *p = *pict;
 
+    if ((res = ff_alloc_packet2(avctx, pkt, s->frame_size + FF_MIN_BUFFER_SIZE)) < 0)
+        return res;
+
     /* First frame needs to be a keyframe */
     if (avctx->frame_number == 0)
         keyframe = 1;
@@ -844,12 +871,6 @@ static int flashsv2_encode_frame(AVCodecContext * avctx, uint8_t * buf,
             keyframe = 1;
     }
 
-    if (buf_size < s->frame_size) {
-        //Conservative upper bound check for compressed data
-        av_log(avctx, AV_LOG_ERROR, "buf_size %d <  %d\n", buf_size, s->frame_size);
-        return -1;
-    }
-
     if (!keyframe
         && avctx->frame_number > s->last_key_frame + avctx->keyint_min) {
         recommend_keyframe(s, &keyframe);
@@ -866,22 +887,26 @@ static int flashsv2_encode_frame(AVCodecContext * avctx, uint8_t * buf,
     if (s->use15_7)
         s->dist = optimum_dist(s);
 
-    res = write_bitstream(s, p->data[0], p->linesize[0], buf, buf_size, keyframe);
+    res = write_bitstream(s, p->data[0], p->linesize[0], pkt->data, pkt->size, keyframe);
 
     if (keyframe) {
         new_key_frame(s);
-        p->pict_type = FF_I_TYPE;
+        p->pict_type = AV_PICTURE_TYPE_I;
         p->key_frame = 1;
         s->last_key_frame = avctx->frame_number;
+        pkt->flags |= AV_PKT_FLAG_KEY;
         av_log(avctx, AV_LOG_DEBUG, "Inserting key frame at frame %d\n", avctx->frame_number);
     } else {
-        p->pict_type = FF_P_TYPE;
+        p->pict_type = AV_PICTURE_TYPE_P;
         p->key_frame = 0;
     }
 
     avctx->coded_frame = p;
 
-    return res;
+    pkt->size = res;
+    *got_packet = 1;
+
+    return 0;
 }
 
 static av_cold int flashsv2_encode_end(AVCodecContext * avctx)
@@ -894,13 +919,13 @@ static av_cold int flashsv2_encode_end(AVCodecContext * avctx)
 }
 
 AVCodec ff_flashsv2_encoder = {
-    "flashsv2",
-    AVMEDIA_TYPE_VIDEO,
-    CODEC_ID_FLASHSV2,
-    sizeof(FlashSV2Context),
-    flashsv2_encode_init,
-    flashsv2_encode_frame,
-    flashsv2_encode_end,
-    .pix_fmts = (enum PixelFormat[]) {PIX_FMT_BGR24, PIX_FMT_NONE},
-    .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video Version 2"),
+    .name           = "flashsv2",
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_FLASHSV2,
+    .priv_data_size = sizeof(FlashSV2Context),
+    .init           = flashsv2_encode_init,
+    .encode2        = flashsv2_encode_frame,
+    .close          = flashsv2_encode_end,
+    .pix_fmts       = (const enum AVPixelFormat[]){ AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE },
+    .long_name      = NULL_IF_CONFIG_SMALL("Flash Screen Video Version 2"),
 };