---
 Changelog              |    1 +
 configure              |    1 +
 doc/general.texi       |    1 +
 libavcodec/Makefile    |    1 +
 libavcodec/allcodecs.c |    1 +
 libavcodec/flashsv.c   |  225 ++++++++++++++++++++++++++++++++++++++++++++++-
 libavcodec/version.h   |    2 +-
 7 files changed, 226 insertions(+), 6 deletions(-)

diff --git a/Changelog b/Changelog
index 00777e4..2eb407e 100644
--- a/Changelog
+++ b/Changelog
@@ -5,6 +5,7 @@ releases are sorted from youngest to oldest.
 version <next>:
 
 - Lots of deprecated API cruft removed
+- Flash Screen Video 2 decoder
 
 
 version 0.7_beta1:
diff --git a/configure b/configure
index c01c551..a10f8cf 100755
--- a/configure
+++ b/configure
@@ -1265,6 +1265,7 @@ flac_decoder_select="golomb"
 flac_encoder_select="golomb lpc"
 flashsv_decoder_select="zlib"
 flashsv_encoder_select="zlib"
+flashsv2_decoder_select="zlib"
 flv_decoder_select="h263_decoder"
 flv_encoder_select="h263_encoder"
 fraps_decoder_select="huffman"
diff --git a/doc/general.texi b/doc/general.texi
index e68e83e..e7bd70d 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -400,6 +400,7 @@ following image formats are supported:
     @tab experimental lossless codec (fourcc: FFV1)
 @item Flash Screen Video v1  @tab  X  @tab  X
     @tab fourcc: FSV1
+@item Flash Screen Video v2  @tab     @tab  X
 @item Flash Video (FLV)      @tab  X  @tab  X
     @tab Sorenson H.263 used in Flash
 @item Fraps                  @tab     @tab  X
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index fad435d..e65271f 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -141,6 +141,7 @@ OBJS-$(CONFIG_FLAC_DECODER)            += flacdec.o 
flacdata.o flac.o
 OBJS-$(CONFIG_FLAC_ENCODER)            += flacenc.o flacdata.o flac.o
 OBJS-$(CONFIG_FLASHSV_DECODER)         += flashsv.o
 OBJS-$(CONFIG_FLASHSV_ENCODER)         += flashsvenc.o
+OBJS-$(CONFIG_FLASHSV2_DECODER)        += flashsv.o
 OBJS-$(CONFIG_FLIC_DECODER)            += flicvideo.o
 OBJS-$(CONFIG_FOURXM_DECODER)          += 4xm.o
 OBJS-$(CONFIG_FRAPS_DECODER)           += fraps.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 40a7e23..57fb799 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -106,6 +106,7 @@ void avcodec_register_all(void)
     REGISTER_ENCDEC  (FFV1, ffv1);
     REGISTER_ENCDEC  (FFVHUFF, ffvhuff);
     REGISTER_ENCDEC  (FLASHSV, flashsv);
+    REGISTER_DECODER (FLASHSV2, flashsv2);
     REGISTER_DECODER (FLIC, flic);
     REGISTER_ENCDEC  (FLV, flv);
     REGISTER_DECODER (FOURXM, fourxm);
diff --git a/libavcodec/flashsv.c b/libavcodec/flashsv.c
index 287cb10..1277da3 100644
--- a/libavcodec/flashsv.c
+++ b/libavcodec/flashsv.c
@@ -55,6 +55,39 @@
 
 #include <zlib.h>
 
+#if CONFIG_FLASHSV2_DECODER
+static const uint32_t ff_flashsv2_default_palette[128] = {
+    0x000000, 0x333333, 0x666666, 0x999999, 0xCCCCCC, 0xFFFFFF,
+    0x330000, 0x660000, 0x990000, 0xCC0000, 0xFF0000, 0x003300,
+    0x006600, 0x009900, 0x00CC00, 0x00FF00, 0x000033, 0x000066,
+    0x000099, 0x0000CC, 0x0000FF, 0x333300, 0x666600, 0x999900,
+    0xCCCC00, 0xFFFF00, 0x003333, 0x006666, 0x009999, 0x00CCCC,
+    0x00FFFF, 0x330033, 0x660066, 0x990099, 0xCC00CC, 0xFF00FF,
+    0xFFFF33, 0xFFFF66, 0xFFFF99, 0xFFFFCC, 0xFF33FF, 0xFF66FF,
+    0xFF99FF, 0xFFCCFF, 0x33FFFF, 0x66FFFF, 0x99FFFF, 0xCCFFFF,
+    0xCCCC33, 0xCCCC66, 0xCCCC99, 0xCCCCFF, 0xCC33CC, 0xCC66CC,
+    0xCC99CC, 0xCCFFCC, 0x33CCCC, 0x66CCCC, 0x99CCCC, 0xFFCCCC,
+    0x999933, 0x999966, 0x9999CC, 0x9999FF, 0x993399, 0x996699,
+    0x99CC99, 0x99FF99, 0x339999, 0x669999, 0xCC9999, 0xFF9999,
+    0x666633, 0x666699, 0x6666CC, 0x6666FF, 0x663366, 0x669966,
+    0x66CC66, 0x66FF66, 0x336666, 0x996666, 0xCC6666, 0xFF6666,
+    0x333366, 0x333399, 0x3333CC, 0x3333FF, 0x336633, 0x339933,
+    0x33CC33, 0x33FF33, 0x663333, 0x993333, 0xCC3333, 0xFF3333,
+    0x003366, 0x336600, 0x660033, 0x006633, 0x330066, 0x663300,
+    0x336699, 0x669933, 0x993366, 0x339966, 0x663399, 0x996633,
+    0x6699CC, 0x99CC66, 0xCC6699, 0x66CC99, 0x9966CC, 0xCC9966,
+    0x99CCFF, 0xCCFF99, 0xFF99CC, 0x99FFCC, 0xCC99FF, 0xFFCC99,
+    0x111111, 0x222222, 0x444444, 0x555555, 0xAAAAAA, 0xBBBBBB,
+    0xDDDDDD, 0xEEEEEE
+};
+#endif /* CONFIG_FLASHSV2_DECODER */
+
+typedef struct BlockInfo {
+    uint8_t *pos;
+    int      size;
+    int      unp_size;
+} BlockInfo;
+
 typedef struct FlashSVContext {
     AVCodecContext *avctx;
     AVFrame frame;
@@ -63,6 +96,11 @@ typedef struct FlashSVContext {
     uint8_t* tmpblock;
     int block_size;
     z_stream zstream;
+    int ver;
+    const uint32_t *pal;
+    int is_keyframe;
+    uint8_t *keyframedata;
+    BlockInfo *blocks;
 } FlashSVContext;
 
 
@@ -79,6 +117,39 @@ static void copy_region(uint8_t *sptr, uint8_t *dptr,
 }
 
 
+static int decode_hybird(const uint8_t *sptr, uint8_t *dptr, int dx, int dy,
+                         int h, int w, int stride, const uint32_t *pal)
+{
+    int x, y;
+    const uint8_t *orig_src = sptr;
+
+    for (y = dx+h; y > dx; y--) {
+        uint8_t *dst = dptr + (y * stride) + dy * 3;
+        for (x = 0; x < w; x++) {
+            if (*sptr & 0x80) {
+                /* 15-bit color */
+                unsigned c = ((sptr[0] & ~0x80) << 8) | sptr[1];
+                unsigned b =  c        & 0x1F;
+                unsigned g = (c >>  5) & 0x1F;
+                unsigned r =  c >> 10;
+                /* 000aabbb -> aa bbb aa  */
+                *dst++ = (b << 3) | (r >> 3);
+                *dst++ = (g << 3) | (g >> 3);
+                *dst++ = (r << 3) | (b >> 3);
+                sptr += 2;
+            } else {
+                /* palette index */
+                uint32_t c = pal[*sptr++];
+                *dst++ =  c        & 0xFF;
+                *dst++ = (c >>  8) & 0xFF;
+                *dst++ =  c >> 16;
+            }
+        }
+    }
+    return sptr - orig_src;
+}
+
+
 static av_cold int flashsv_decode_init(AVCodecContext *avctx)
 {
     FlashSVContext *s = avctx->priv_data;
@@ -95,11 +166,54 @@ static av_cold int flashsv_decode_init(AVCodecContext 
*avctx)
     }
     avctx->pix_fmt = PIX_FMT_BGR24;
     s->frame.data[0] = NULL;
+    s->ver = 1;
 
     return 0;
 }
 
 
+static av_cold int flashsv2_decode_init(AVCodecContext *avctx)
+{
+    FlashSVContext *s = avctx->priv_data;
+    flashsv_decode_init(avctx);
+    s->pal = ff_flashsv2_default_palette;
+    s->ver = 2;
+
+    return 0;
+}
+
+static void flashsv2_prime(FlashSVContext *s, uint8_t *src,
+                           int size, int unp_size)
+{
+    z_stream zs;
+    int ret;
+    uint8_t buf[65536*2];
+    zs.zalloc = NULL;
+    zs.zfree  = NULL;
+    zs.opaque = NULL;
+
+    s->zstream.next_in   = src;
+    s->zstream.avail_in  = size;
+    s->zstream.next_out  = s->tmpblock;
+    s->zstream.avail_out = s->block_size*3;
+    ret = inflate(&(s->zstream), Z_SYNC_FLUSH);
+
+    deflateInit(&zs, 3);
+    zs.next_in   = s->tmpblock;
+    zs.avail_in  = s->block_size * 3 - s->zstream.avail_out;
+    zs.next_out  = buf;
+    zs.avail_out = sizeof(buf);
+    deflate(&zs, Z_SYNC_FLUSH);
+
+    inflateReset(&s->zstream);
+
+    s->zstream.next_in   = buf;
+    s->zstream.avail_in  = sizeof(buf) - zs.avail_out;
+    s->zstream.next_out  = s->tmpblock;
+    s->zstream.avail_out = s->block_size*3;
+    ret = inflate(&(s->zstream), Z_SYNC_FLUSH);
+}
+
 static int flashsv_decode_frame(AVCodecContext *avctx,
                                     void *data, int *data_size,
                                     AVPacket *avpkt)
@@ -124,6 +238,18 @@ static int flashsv_decode_frame(AVCodecContext *avctx,
     s->block_height= 16* (get_bits(&gb, 4)+1);
     s->image_height=     get_bits(&gb,12);
 
+    if (s->ver == 2) {
+        skip_bits(&gb, 6);
+        if (get_bits1(&gb)) {
+            av_log(avctx, AV_LOG_ERROR, "FIXME iframe not implemented yet\n");
+            return -1;
+        }
+        if (get_bits1(&gb)) {
+            av_log(avctx, AV_LOG_ERROR, "FIXME custom palette not implemented 
yet\n");
+            return -1;
+        }
+    }
+
     /* calculate amount of blocks and the size of the border blocks */
     h_blocks = s->image_width / s->block_width;
     h_part = s->image_width % s->block_width;
@@ -134,7 +260,7 @@ static int flashsv_decode_frame(AVCodecContext *avctx,
      * is large enough, if not, get a larger one */
     if(s->block_size < s->block_width*s->block_height) {
         av_free(s->tmpblock);
-        if ((s->tmpblock = av_malloc(3*s->block_width*s->block_height)) == 
NULL) {
+        if ((s->tmpblock = av_malloc(2 * 3 * s->block_width * 
s->block_height)) == NULL) {
             av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression 
buffer.\n");
             return -1;
         }
@@ -155,9 +281,20 @@ static int flashsv_decode_frame(AVCodecContext *avctx,
         return -1;
     }
 
-    av_log(avctx, AV_LOG_DEBUG, "image: %dx%d block: %dx%d num: %dx%d part: 
%dx%d\n",
+    /* we care for keyframes only in Screen Video v2 */
+    s->is_keyframe = (avpkt->flags & AV_PKT_FLAG_KEY) && (s->ver == 2);
+    if (s->is_keyframe) {
+        s->keyframedata = av_realloc(s->keyframedata, avpkt->size);
+        memcpy(s->keyframedata, avpkt->data, avpkt->size);
+        s->blocks = av_realloc(s->blocks,
+                               (v_blocks + !!v_part) * (h_blocks + !!h_part)
+                               * sizeof(s->blocks[0]));
+    }
+
+    av_log(avctx, AV_LOG_DEBUG,
+           "image: %dx%d block: %dx%d num: %dx%d part: %dx%d keyframe: %d\n",
         s->image_width, s->image_height, s->block_width, s->block_height,
-        h_blocks, v_blocks, h_part, v_part);
+        h_blocks, v_blocks, h_part, v_part, s->is_keyframe);
 
     s->frame.reference = 1;
     s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | 
FF_BUFFER_HINTS_REUSABLE;
@@ -181,6 +318,9 @@ static int flashsv_decode_frame(AVCodecContext *avctx,
             int ws = (i<h_blocks)?s->block_width:h_part; // size of block
 
             /* get the size of the compressed zlib chunk */
+            int color_depth = 0, zlibprime_curr = 0, zlibprime_prev = 0, 
has_diff = 0;
+            int diff_start = 0, diff_height = hs;
+
             int size = get_bits(&gb, 16);
             if (8 * size > get_bits_left(&gb)) {
                 avctx->release_buffer(avctx, &s->frame);
@@ -188,6 +328,41 @@ static int flashsv_decode_frame(AVCodecContext *avctx,
                 return -1;
             }
 
+            if (s->ver == 2 && size) {
+                skip_bits(&gb, 3);
+                color_depth    = get_bits(&gb, 2);
+                has_diff       = get_bits1(&gb);
+                zlibprime_curr = get_bits1(&gb);
+                zlibprime_prev = get_bits1(&gb);
+
+                if (color_depth != 0 && color_depth != 2) {
+                    av_log(avctx, AV_LOG_ERROR,
+                           "%dx%d invalid color depth %d\n", i, j, 
color_depth);
+                    return -1;
+                }
+
+                if (has_diff) {
+                    diff_start  = get_bits(&gb, 8);
+                    diff_height = get_bits(&gb, 8);
+                    av_log(avctx, AV_LOG_DEBUG,
+                           "%dx%d diff start %d height %d\n",
+                           i, j, diff_start, diff_height);
+                    size -= 2;
+                }
+
+                if (zlibprime_prev)
+                    av_log(avctx, AV_LOG_DEBUG, "%dx%d zlibprime_prev\n", i, 
j);
+
+                if (zlibprime_curr) {
+                    int col = get_bits(&gb, 8);
+                    int row = get_bits(&gb, 8);
+                    av_log(avctx, AV_LOG_DEBUG, "%dx%d zlibprime_curr 
%dx%d\n", i, j, col, row);
+                    size -= 2;
+                    return -1; //NIY
+                }
+                size--; // account for flags byte
+            }
+
             if (size == 0) {
                 /* no change, don't do anything */
             } else {
@@ -198,24 +373,44 @@ static int flashsv_decode_frame(AVCodecContext *avctx,
                     av_log(avctx, AV_LOG_ERROR, "error in decompression 
(reset) of block %dx%d\n", i, j);
                     /* return -1; */
                 }
+                if (zlibprime_curr || zlibprime_prev) {
+                    int idx = i + j * (h_blocks + !!h_part);
+                    flashsv2_prime(s, s->blocks[idx].pos, s->blocks[idx].size,
+                                   s->blocks[idx].unp_size);
+                }
                 s->zstream.next_in = buf+(get_bits_count(&gb)/8);
                 s->zstream.avail_in = size;
                 s->zstream.next_out = s->tmpblock;
                 s->zstream.avail_out = s->block_size*3;
-                ret = inflate(&(s->zstream), Z_FINISH);
+                ret = inflate(&(s->zstream), Z_SYNC_FLUSH);
                 if (ret == Z_DATA_ERROR)
                 {
                     av_log(avctx, AV_LOG_ERROR, "Zlib resync occurred\n");
                     inflateSync(&(s->zstream));
                     ret = inflate(&(s->zstream), Z_FINISH);
                 }
+                if (s->is_keyframe) {
+                    s->blocks[i + j * (h_blocks + !!h_part)].pos      = 
s->keyframedata + (get_bits_count(&gb) / 8);
+                    s->blocks[i + j * (h_blocks + !!h_part)].size     = size;
+                    s->blocks[i + j * (h_blocks + !!h_part)].unp_size = 
s->block_size * 3 - s->zstream.avail_out;
+                }
 
                 if ((ret != Z_OK) && (ret != Z_STREAM_END))
                 {
                     av_log(avctx, AV_LOG_ERROR, "error in decompression of 
block %dx%d: %d\n", i, j, ret);
                     /* return -1; */
                 }
-                copy_region(s->tmpblock, s->frame.data[0], 
s->image_height-(hp+hs+1), wp, hs, ws, s->frame.linesize[0]);
+
+                if (color_depth) {
+                    /* hybird 15-bit/palette mode */
+                    decode_hybird(s->tmpblock, s->frame.data[0],
+                                  s->image_height - (hp + 1 + diff_start + 
diff_height),
+                                  wp, diff_height, ws, s->frame.linesize[0], 
s->pal);
+                } else {
+                    copy_region(s->tmpblock, s->frame.data[0],
+                                s->image_height - (hp + 1 + diff_start + 
diff_height),
+                                wp, diff_height, ws, s->frame.linesize[0]);
+                }
                 skip_bits_long(&gb, 8*size);   /* skip the consumed bits */
             }
         }
@@ -244,10 +439,13 @@ static av_cold int flashsv_decode_end(AVCodecContext 
*avctx)
     /* free the tmpblock */
     av_free(s->tmpblock);
 
+    av_freep(&s->keyframedata);
+    av_freep(&s->blocks);
     return 0;
 }
 
 
+#if CONFIG_FLASHSV_DECODER
 AVCodec ff_flashsv_decoder = {
     "flashsv",
     AVMEDIA_TYPE_VIDEO,
@@ -261,3 +459,20 @@ AVCodec ff_flashsv_decoder = {
     .pix_fmts = (const enum PixelFormat[]){PIX_FMT_BGR24, PIX_FMT_NONE},
     .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video v1"),
 };
+#endif /* CONFIG_FLASHSV_DECODER */
+
+#if CONFIG_FLASHSV2_DECODER
+AVCodec ff_flashsv2_decoder = {
+    "flashsv2",
+    AVMEDIA_TYPE_VIDEO,
+    CODEC_ID_FLASHSV2,
+    sizeof(FlashSVContext),
+    flashsv2_decode_init,
+    NULL,
+    flashsv_decode_end,
+    flashsv_decode_frame,
+    CODEC_CAP_DR1,
+    .pix_fmts = (const enum PixelFormat[]){PIX_FMT_BGR24, PIX_FMT_NONE},
+    .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video v2"),
+};
+#endif /* CONFIG_FLASHSV2_DECODER */
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 487e7a5..0cb2564 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -21,7 +21,7 @@
 #define AVCODEC_VERSION_H
 
 #define LIBAVCODEC_VERSION_MAJOR 53
-#define LIBAVCODEC_VERSION_MINOR  1
+#define LIBAVCODEC_VERSION_MINOR  2
 #define LIBAVCODEC_VERSION_MICRO  0
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
-- 
1.7.1

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to