---
* This codec is known as M$ ATC Screen commercially but internally it's uses
MSS3_ScreenCodec class, hence the file name (but codec ID is made after its
FOURCC though).

* Model2 and Model256 are special cases of model. They are decoded the same
except that Model256 uses an additional secondary lookup in order to speed
decoding. These special cases are done for both speed and memory
considerations (e.g. for 125 models in each of 3 BlockCoders this saves >700kB)

* Dsputil is not used because interframes are decoded with offsets and they may
be (and are!) not multiple of 8. And dsputil functions assume aligned output.

* In DCT first two variables have multipliers -39409 and 39410. This is the way
it was in the reference decoder.

* By averaging this and MSS1 any j-b can obtain MSS2 decoder ;)

* It passed "make check" too.
---
 Changelog              |    1 +
 doc/general.texi       |    2 +
 libavcodec/Makefile    |    1 +
 libavcodec/allcodecs.c |    1 +
 libavcodec/avcodec.h   |    1 +
 libavcodec/mss3.c      |  969 ++++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/riff.c     |    1 +
 7 files changed, 976 insertions(+), 0 deletions(-)
 create mode 100644 libavcodec/mss3.c

diff --git a/Changelog b/Changelog
index 95f79bc..39ad8a3 100644
--- a/Changelog
+++ b/Changelog
@@ -30,6 +30,7 @@ version <next>:
 - Microsoft Screen 1 decoder
 - join audio filter
 - audio channel mapping filter
+- Microsoft ATC Screen decoder
 
 
 version 0.8:
diff --git a/doc/general.texi b/doc/general.texi
index 28e89f0..b7042f0 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -531,6 +531,8 @@ following image formats are supported:
 @item LCL (LossLess Codec Library) ZLIB  @tab  E  @tab  E
 @item LOCO                   @tab     @tab  X
 @item lossless MJPEG         @tab  X  @tab  X
+@item Microsoft ATC Screen   @tab     @tab  X
+    @tab Also known as Microsoft Screen 3.
 @item Microsoft RLE          @tab     @tab  X
 @item Microsoft Screen 1     @tab     @tab  X
     @tab Also known as Windows Media Video V7 Screen.
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 8204a18..efedee9 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -292,6 +292,7 @@ OBJS-$(CONFIG_MSMPEG4V3_ENCODER)       += msmpeg4.o 
msmpeg4enc.o msmpeg4data.o \
                                           h263dec.o h263.o ituh263dec.o        
\
                                           mpeg4videodec.o
 OBJS-$(CONFIG_MSRLE_DECODER)           += msrle.o msrledec.o
+OBJS-$(CONFIG_MSA1_DECODER)            += mss3.o
 OBJS-$(CONFIG_MSS1_DECODER)            += mss1.o
 OBJS-$(CONFIG_MSVIDEO1_DECODER)        += msvideo1.o
 OBJS-$(CONFIG_MSZH_DECODER)            += lcldec.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index f6a2df8..cb08e33 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -152,6 +152,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER (MPEG4_VDPAU, mpeg4_vdpau);
     REGISTER_DECODER (MPEG_VDPAU, mpeg_vdpau);
     REGISTER_DECODER (MPEG1_VDPAU, mpeg1_vdpau);
+    REGISTER_DECODER (MSA1, msa1);
     REGISTER_DECODER (MSMPEG4V1, msmpeg4v1);
     REGISTER_ENCDEC  (MSMPEG4V2, msmpeg4v2);
     REGISTER_ENCDEC  (MSMPEG4V3, msmpeg4v3);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 5ba021c..2b70b96 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -256,6 +256,7 @@ enum CodecID {
     CODEC_ID_XBM,
     CODEC_ID_ZEROCODEC,
     CODEC_ID_MSS1,
+    CODEC_ID_MSA1,
 
     /* various PCM "codecs" */
     CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start 
of audio codecs
diff --git a/libavcodec/mss3.c b/libavcodec/mss3.c
new file mode 100644
index 0000000..4f30355
--- /dev/null
+++ b/libavcodec/mss3.c
@@ -0,0 +1,969 @@
+/*
+ * Microsoft Screen 3 (aka Microsoft ATC Screen) decoder
+ * Copyright (c) 2012 Konstantin Shishkov
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Microsoft Screen 3 (aka Microsoft ATC Screen) decoder
+ */
+
+#include "avcodec.h"
+#include "bytestream.h"
+
+#define HEADER_SIZE 27
+
+#define MODEL2_SCALE       13
+#define MODEL_SCALE        15
+#define MODEL256_SEC_SCALE  9
+
+typedef struct Model2 {
+    int      upd_val, till_rescale;
+    unsigned zero_freq,  zero_weight;
+    unsigned total_freq, total_weight;
+} Model2;
+
+typedef struct Model {
+    int weights[16], freqs[16];
+    int num_syms;
+    int tot_weight;
+    int upd_val, max_upd_val, till_rescale;
+} Model;
+
+typedef struct Model256 {
+    int weights[256], freqs[256];
+    int tot_weight;
+    int secondary[68];
+    int sec_size;
+    int upd_val, max_upd_val, till_rescale;
+} Model256;
+
+#define RAC_BOTTOM 0x01000000
+typedef struct RangeCoder {
+    const uint8_t *src, *src_end;
+
+    uint32_t range, low;
+    int got_error;
+} RangeCoder;
+
+enum BlockType {
+    FILL_BLOCK = 0,
+    IMAGE_BLOCK,
+    DCT_BLOCK,
+    HAAR_BLOCK,
+    SKIP_BLOCK
+};
+
+typedef struct BlockTypeContext {
+    int      last_type;
+    Model    bt_model[5];
+} BlockTypeContext;
+
+typedef struct FillBlockCoder {
+    int      fill_val;
+    Model    coef_model;
+} FillBlockCoder;
+
+typedef struct ImageBlockCoder {
+    Model256 esc_model, vec_entry_model;
+    Model    vec_size_model;
+    Model    vq_model[125];
+} ImageBlockCoder;
+
+typedef struct DCTBlockCoder {
+    int      *prev_dc;
+    int      prev_dc_stride;
+    int      prev_dc_height;
+    int      quality;
+    uint16_t qmat[64];
+    Model    dc_model;
+    Model2   sign_model;
+    Model256 ac_model;
+} DCTBlockCoder;
+
+typedef struct HaarBlockCoder {
+    int      quality, scale;
+    Model256 coef_model;
+    Model    coef_hi_model;
+} HaarBlockCoder;
+
+typedef struct MSS3Context {
+    AVCodecContext   *avctx;
+    AVFrame          pic;
+
+    int              got_error;
+    RangeCoder       coder;
+    BlockTypeContext btype[3];
+    FillBlockCoder   fill_coder[3];
+    ImageBlockCoder  image_coder[3];
+    DCTBlockCoder    dct_coder[3];
+    HaarBlockCoder   haar_coder[3];
+
+    int              dctblock[64];
+    int              hblock[16 * 16];
+} MSS3Context;
+
+static const uint8_t mss3_luma_quant[64] = {
+    16,  11,  10,  16,  24,  40,  51,  61,
+    12,  12,  14,  19,  26,  58,  60,  55,
+    14,  13,  16,  24,  40,  57,  69,  56,
+    14,  17,  22,  29,  51,  87,  80,  62,
+    18,  22,  37,  56,  68, 109, 103,  77,
+    24,  35,  55,  64,  81, 104, 113,  92,
+    49,  64,  78,  87, 103, 121, 120, 101,
+    72,  92,  95,  98, 112, 100, 103,  99
+};
+
+static const uint8_t mss3_chroma_quant[64] = {
+    17, 18, 24, 47, 99, 99, 99, 99,
+    18, 21, 26, 66, 99, 99, 99, 99,
+    24, 26, 56, 99, 99, 99, 99, 99,
+    47, 66, 99, 99, 99, 99, 99, 99,
+    99, 99, 99, 99, 99, 99, 99, 99,
+    99, 99, 99, 99, 99, 99, 99, 99,
+    99, 99, 99, 99, 99, 99, 99, 99,
+    99, 99, 99, 99, 99, 99, 99, 99
+};
+
+const uint8_t zigzag_scan[64] = {
+    0,   1,  8, 16,  9,  2,  3, 10,
+    17, 24, 32, 25, 18, 11,  4,  5,
+    12, 19, 26, 33, 40, 48, 41, 34,
+    27, 20, 13,  6,  7, 14, 21, 28,
+    35, 42, 49, 56, 57, 50, 43, 36,
+    29, 22, 15, 23, 30, 37, 44, 51,
+    58, 59, 52, 45, 38, 31, 39, 46,
+    53, 60, 61, 54, 47, 55, 62, 63
+};
+
+
+static void model2_reset(Model2 *m)
+{
+    m->zero_weight  = 1;
+    m->total_weight = 2;
+    m->zero_freq    = 0x1000;
+    m->total_freq   = 0x2000;
+    m->upd_val      = 4;
+    m->till_rescale = 4;
+}
+
+static void model2_update(Model2 *m, int bit)
+{
+    unsigned scale;
+
+    if (!bit)
+        m->zero_weight++;
+    m->till_rescale--;
+    if (m->till_rescale)
+        return;
+
+    m->total_weight += m->upd_val;
+    if (m->total_weight > 0x2000) {
+        m->total_weight = (m->total_weight + 1) >> 1;
+        m->zero_weight  = (m->zero_weight  + 1) >> 1;
+        if (m->total_weight == m->zero_weight)
+            m->total_weight = m->zero_weight + 1;
+    }
+    m->upd_val = (m->upd_val * 5) >> 2;
+    if (m->upd_val > 64)
+        m->upd_val = 64;
+    scale = 0x80000000u / m->total_weight;
+    m->zero_freq    = (m->zero_weight  * scale) >> 18;
+    m->total_freq   = (m->total_weight * scale) >> 18;
+    m->till_rescale = m->upd_val;
+}
+
+static void model_update(Model *m, int val)
+{
+    int i, sum = 0;
+    unsigned scale;
+
+    m->weights[val]++;
+    m->till_rescale--;
+    if (m->till_rescale)
+        return;
+    m->tot_weight += m->upd_val;
+
+    if (m->tot_weight > 0x8000) {
+        m->tot_weight = 0;
+        for (i = 0; i < m->num_syms; i++) {
+            m->weights[i]  = (m->weights[i] + 1) >> 1;
+            m->tot_weight +=  m->weights[i];
+        }
+    }
+    scale = 0x80000000u / m->tot_weight;
+    for (i = 0; i < m->num_syms; i++) {
+        m->freqs[i] = (sum * scale) >> 16;
+        sum += m->weights[i];
+    }
+
+    m->upd_val = (m->upd_val * 5) >> 2;
+    if (m->upd_val > m->max_upd_val)
+        m->upd_val = m->max_upd_val;
+    m->till_rescale = m->upd_val;
+}
+
+static void model_reset(Model *m)
+{
+    int i;
+
+    m->tot_weight   = 0;
+    for (i = 0; i < m->num_syms - 1; i++)
+        m->weights[i] = 1;
+    m->weights[m->num_syms - 1] = 0;
+
+    m->upd_val      = m->num_syms;
+    m->till_rescale = 1;
+    model_update(m, m->num_syms - 1);
+    m->till_rescale =
+    m->upd_val      = (m->num_syms + 6) >> 1;
+}
+
+static av_cold void model_init(Model *m, int num_syms)
+{
+    m->num_syms    = num_syms;
+    m->max_upd_val = 8 * num_syms + 48;
+
+    model_reset(m);
+}
+
+static void model256_update(Model256 *m, int val)
+{
+    int i, sum = 0;
+    unsigned scale;
+    int send, sidx = 1;
+
+    m->weights[val]++;
+    m->till_rescale--;
+    if (m->till_rescale)
+        return;
+    m->tot_weight += m->upd_val;
+
+    if (m->tot_weight > 0x8000) {
+        m->tot_weight = 0;
+        for (i = 0; i < 256; i++) {
+            m->weights[i]  = (m->weights[i] + 1) >> 1;
+            m->tot_weight +=  m->weights[i];
+        }
+    }
+    scale = 0x80000000u / m->tot_weight;
+    m->secondary[0] = 0;
+    for (i = 0; i < 256; i++) {
+        m->freqs[i] = (sum * scale) >> 16;
+        sum += m->weights[i];
+        send = m->freqs[i] >> MODEL256_SEC_SCALE;
+        while (sidx <= send)
+            m->secondary[sidx++] = i - 1;
+    }
+    while (sidx < m->sec_size)
+        m->secondary[sidx++] = 255;
+
+    m->upd_val = (m->upd_val * 5) >> 2;
+    if (m->upd_val > m->max_upd_val)
+        m->upd_val = m->max_upd_val;
+    m->till_rescale = m->upd_val;
+}
+
+static void model256_reset(Model256 *m)
+{
+    int i;
+
+    for (i = 0; i < 255; i++)
+        m->weights[i] = 1;
+    m->weights[255] = 0;
+
+    m->tot_weight   = 0;
+    m->upd_val      = 256;
+    m->till_rescale = 1;
+    model256_update(m, 255);
+    m->till_rescale =
+    m->upd_val      = (256 + 6) >> 1;
+}
+
+static av_cold void model256_init(Model256 *m)
+{
+    m->max_upd_val = 8 * 256 + 48;
+    m->sec_size    = (1 << 6) + 2;
+
+    model256_reset(m);
+}
+
+static void rac_init(RangeCoder *c, const uint8_t *src, int size)
+{
+    int i;
+
+    c->src       = src;
+    c->src_end   = src + size;
+    c->low       = 0;
+    for (i = 0; i < FFMIN(size, 4); i++)
+        c->low = (c->low << 8) | *c->src++;
+    c->range     = 0xFFFFFFFF;
+    c->got_error = 0;
+}
+
+static void rac_normalise(RangeCoder *c)
+{
+    for (;;) {
+        c->range <<= 8;
+        c->low   <<= 8;
+        if (c->src < c->src_end) {
+            c->low |= *c->src++;
+        } else if (!c->low) {
+            c->got_error = 1;
+            return;
+        }
+        if (c->range >= RAC_BOTTOM)
+            return;
+    }
+}
+
+static int rac_get_bit(RangeCoder *c)
+{
+    int bit;
+
+    c->range >>= 1;
+
+    bit = (c->range <= c->low);
+    if (bit)
+        c->low -= c->range;
+
+    if (c->range < RAC_BOTTOM)
+        rac_normalise(c);
+
+    return bit;
+}
+
+static int rac_get_bits(RangeCoder *c, int nbits)
+{
+    int val;
+
+    c->range >>= nbits;
+    val = c->low / c->range;
+    c->low -= c->range * val;
+
+    if (c->range < RAC_BOTTOM)
+        rac_normalise(c);
+
+    return val;
+}
+
+static int rac_get_model2_sym(RangeCoder *c, Model2 *m)
+{
+    int bit, helper;
+
+    helper = m->zero_freq * (c->range >> MODEL2_SCALE);
+    bit    = (c->low >= helper);
+    if (bit) {
+        c->low   -= helper;
+        c->range -= helper;
+    } else {
+        c->range  = helper;
+    }
+
+    if (c->range < RAC_BOTTOM)
+        rac_normalise(c);
+
+    model2_update(m, bit);
+
+    return bit;
+}
+
+static int rac_get_model_sym(RangeCoder *c, Model *m)
+{
+    int prob, prob2, helper, val;
+    int end, end2;
+
+    prob       = 0;
+    prob2      = c->range;
+    c->range >>= MODEL_SCALE;
+    val        = 0;
+    end        = m->num_syms >> 1;
+    end2       = m->num_syms;
+    do {
+        helper = m->freqs[end] * c->range;
+        if (helper <= c->low) {
+            val   = end;
+            prob  = helper;
+        } else {
+            end2  = end;
+            prob2 = helper;
+        }
+        end = (end2 + val) >> 1;
+    } while (end != val);
+    c->low  -= prob;
+    c->range = prob2 - prob;
+    if (c->range < RAC_BOTTOM)
+        rac_normalise(c);
+
+    model_update(m, val);
+
+    return val;
+}
+
+static int rac_get_model256_sym(RangeCoder *c, Model256 *m)
+{
+    int prob, prob2, helper, val;
+    int start, end;
+    int ssym;
+
+    prob2      = c->range;
+    c->range >>= MODEL_SCALE;
+
+    helper     = c->low / c->range;
+    ssym       = helper >> MODEL256_SEC_SCALE;
+    val        = m->secondary[ssym];
+
+    end = start = m->secondary[ssym + 1] + 1;
+    while (end > val + 1) {
+        ssym = (end + val) >> 1;
+        if (m->freqs[ssym] <= helper) {
+            end = start;
+            val = ssym;
+        } else {
+            end   = (end + val) >> 1;
+            start = ssym;
+        }
+    }
+    prob = m->freqs[val] * c->range;
+    if (val != 255)
+        prob2 = m->freqs[val + 1] * c->range;
+
+    c->low  -= prob;
+    c->range = prob2 - prob;
+    if (c->range < RAC_BOTTOM)
+        rac_normalise(c);
+
+    model256_update(m, val);
+
+    return val;
+}
+
+static int decode_block_type(RangeCoder *c, BlockTypeContext *bt)
+{
+    bt->last_type = rac_get_model_sym(c, &bt->bt_model[bt->last_type]);
+
+    return bt->last_type;
+}
+
+static int decode_coeff(RangeCoder *c, Model *m)
+{
+    int val, sign;
+
+    val = rac_get_model_sym(c, m);
+    if (val) {
+        sign = rac_get_bit(c);
+        if (val > 1) {
+            val--;
+            val = (1 << val) + rac_get_bits(c, val);
+        }
+        if (!sign)
+            val = -val;
+    }
+
+    return val;
+}
+
+static void decode_fill_block(RangeCoder *c, FillBlockCoder *fc,
+                              uint8_t *dst, int stride, int block_size)
+{
+    int i;
+
+    fc->fill_val += decode_coeff(c, &fc->coef_model);
+
+    for (i = 0; i < block_size; i++, dst += stride)
+        memset(dst, fc->fill_val, block_size);
+}
+
+static void decode_image_block(RangeCoder *c, ImageBlockCoder *ic,
+                               uint8_t *dst, int stride, int block_size)
+{
+    int i, j;
+    int vec_size;
+    int vec[4];
+    int prev_line[16];
+    int A, B, C;
+
+    vec_size = rac_get_model_sym(c, &ic->vec_size_model) + 2;
+    for (i = 0; i < vec_size; i++)
+        vec[i] = rac_get_model256_sym(c, &ic->vec_entry_model);
+    for (; i < 4; i++)
+        vec[i] = 0;
+    memset(prev_line, 0, sizeof(prev_line));
+
+    for (j = 0; j < block_size; j++) {
+        A = 0;
+        B = 0;
+        for (i = 0; i < block_size; i++) {
+            C = B;
+            B = prev_line[i];
+            A = rac_get_model_sym(c, &ic->vq_model[A + B * 5 + C * 25]);
+
+            prev_line[i] = A;
+            if (A < 4)
+               dst[i] = vec[A];
+            else
+               dst[i] = rac_get_model256_sym(c, &ic->esc_model);
+        }
+        dst += stride;
+    }
+}
+
+static int decode_dct(RangeCoder *c, DCTBlockCoder *bc, int *block,
+                      int bx, int by)
+{
+    int skip, val, sign, pos = 1, zz_pos, dc;
+    int blk_pos = bx + by * bc->prev_dc_stride;
+
+    memset(block, 0, sizeof(*block) * 64);
+
+    dc = decode_coeff(c, &bc->dc_model);
+    if (by) {
+        if (bx) {
+            int l, tl, t;
+
+            l  = bc->prev_dc[blk_pos - 1];
+            tl = bc->prev_dc[blk_pos - 1 - bc->prev_dc_stride];
+            t  = bc->prev_dc[blk_pos     - bc->prev_dc_stride];
+
+            if (FFABS(t - tl) <= FFABS(l - tl))
+                dc += l;
+            else
+                dc += t;
+        } else {
+            dc += bc->prev_dc[blk_pos - bc->prev_dc_stride];
+        }
+    } else if (bx) {
+        dc += bc->prev_dc[bx - 1];
+    }
+    bc->prev_dc[blk_pos] = dc;
+    block[0]             = dc * bc->qmat[0];
+
+    while (pos < 64) {
+        val = rac_get_model256_sym(c, &bc->ac_model);
+        if (!val)
+            return 0;
+        if (val == 0xF0) {
+            pos += 16;
+            continue;
+        }
+        skip = val >> 4;
+        val  = val & 0xF;
+        if (!val)
+            return -1;
+        pos += skip;
+        if (pos >= 64)
+            return -1;
+
+        sign = rac_get_model2_sym(c, &bc->sign_model);
+        if (val > 1) {
+            val--;
+            val = (1 << val) + rac_get_bits(c, val);
+        }
+        if (!sign)
+            val = -val;
+
+        zz_pos = zigzag_scan[pos];
+        block[zz_pos] = val * bc->qmat[zz_pos];
+        pos++;
+    }
+
+    return pos == 64 ? 0 : -1;
+}
+
+#define DCT_TEMPLATE(blk, step, SOP, shift) \
+    const int t0 = -39409 * blk[7 * step] -  58980 * blk[1 * step]; \
+    const int t1 =  39410 * blk[1 * step] -  58980 * blk[7 * step]; \
+    const int t2 = -33410 * blk[5 * step] - 167963 * blk[3 * step]; \
+    const int t3 =  33410 * blk[3 * step] - 167963 * blk[5 * step]; \
+    const int t4 = blk[3 * step] + blk[7 * step]; \
+    const int t5 = blk[1 * step] + blk[5 * step]; \
+    const int t6 =  77062 * t4 + 51491 * t5; \
+    const int t7 =  77062 * t5 - 51491 * t4; \
+    const int t8 =  35470 * blk[2 * step] - 85623 * blk[6 * step]; \
+    const int t9 =  35470 * blk[6 * step] + 85623 * blk[2 * step]; \
+    const int tA = SOP(blk[0 * step] - blk[4 * step]); \
+    const int tB = SOP(blk[0 * step] + blk[4 * step]); \
+\
+    blk[0 * step] = (  t1 + t6  + t9 + tB) >> shift; \
+    blk[1 * step] = (  t3 + t7  + t8 + tA) >> shift; \
+    blk[2 * step] = (  t2 + t6  - t8 + tA) >> shift; \
+    blk[3 * step] = (  t0 + t7  - t9 + tB) >> shift; \
+    blk[4 * step] = (-(t0 + t7) - t9 + tB) >> shift; \
+    blk[5 * step] = (-(t2 + t6) - t8 + tA) >> shift; \
+    blk[6 * step] = (-(t3 + t7) + t8 + tA) >> shift; \
+    blk[7 * step] = (-(t1 + t6) + t9 + tB) >> shift; \
+\
+
+#define SOP_ROW(a) ((a) << 16) + 0x2000
+#define SOP_COL(a) ((a + 32) << 16)
+
+static void dct_put(uint8_t *dst, int stride, int *block)
+{
+    int i, j;
+    int *ptr;
+
+    ptr = block;
+    for (i = 0; i < 8; i++) {
+        DCT_TEMPLATE(ptr, 1, SOP_ROW, 13);
+        ptr += 8;
+    }
+
+    ptr = block;
+    for (i = 0; i < 8; i++) {
+        DCT_TEMPLATE(ptr, 8, SOP_COL, 22);
+        ptr++;
+    }
+
+    ptr = block;
+    for (j = 0; j < 8; j++) {
+        for (i = 0; i < 8; i++)
+            dst[i] = av_clip_uint8(ptr[i] + 128);
+        dst += stride;
+        ptr += 8;
+    }
+}
+
+static void decode_dct_block(RangeCoder *c, DCTBlockCoder *bc,
+                             uint8_t *dst, int stride, int block_size,
+                             int *block, int mb_x, int mb_y)
+{
+    int i, j;
+    int bx, by;
+    int nblocks = block_size >> 3;
+
+    bx = mb_x * nblocks;
+    by = mb_y * nblocks;
+
+    for (j = 0; j < nblocks; j++) {
+        for (i = 0; i < nblocks; i++) {
+            if (decode_dct(c, bc, block, bx + i, by + j)) {
+                c->got_error = 1;
+                return;
+            }
+            dct_put(dst + i * 8, stride, block);
+        }
+        dst += 8 * stride;
+    }
+}
+
+static void decode_haar_block(RangeCoder *c, HaarBlockCoder *hc,
+                              uint8_t *dst, int stride, int block_size,
+                              int *block)
+{
+    const int hsize = block_size >> 1;
+    int A, B, C, D, t1, t2, t3, t4;
+    int i, j;
+
+    for (j = 0; j < block_size; j++) {
+        for (i = 0; i < block_size; i++) {
+            if (i < hsize && j < hsize)
+                block[i] = rac_get_model256_sym(c, &hc->coef_model);
+            else
+                block[i] = decode_coeff(c, &hc->coef_hi_model);
+            block[i] *= hc->scale;
+        }
+        block += block_size;
+    }
+    block -= block_size * block_size;
+
+    for (j = 0; j < hsize; j++) {
+        for (i = 0; i < hsize; i++) {
+            A = block[i];
+            B = block[i + hsize];
+            C = block[i + hsize * block_size];
+            D = block[i + hsize * block_size + hsize];
+
+            t1 = A - B;
+            t2 = C - D;
+            t3 = A + B;
+            t4 = C + D;
+            dst[i * 2]              = av_clip_uint8(t1 - t2);
+            dst[i * 2 + stride]     = av_clip_uint8(t1 + t2);
+            dst[i * 2 + 1]          = av_clip_uint8(t3 - t4);
+            dst[i * 2 + 1 + stride] = av_clip_uint8(t3 + t4);
+        }
+        block += block_size;
+        dst   += stride * 2;
+    }
+}
+
+static void gen_quant_mat(uint16_t *qmat, const uint8_t *ref, float scale)
+{
+    int i;
+
+    for (i = 0; i < 64; i++)
+        qmat[i] = (uint16_t)(ref[i] * scale + 50.0) / 100;
+}
+
+static void reset_coders(MSS3Context *ctx, int quality)
+{
+    int i, j;
+
+    for (i = 0; i < 3; i++) {
+        ctx->btype[i].last_type = SKIP_BLOCK;
+        for (j = 0; j < 5; j++)
+            model_reset(&ctx->btype[i].bt_model[j]);
+        ctx->fill_coder[i].fill_val = 0;
+        model_reset(&ctx->fill_coder[i].coef_model);
+        model256_reset(&ctx->image_coder[i].esc_model);
+        model256_reset(&ctx->image_coder[i].vec_entry_model);
+        model_reset(&ctx->image_coder[i].vec_size_model);
+        for (j = 0; j < 125; j++)
+            model_reset(&ctx->image_coder[i].vq_model[j]);
+        if (ctx->dct_coder[i].quality != quality) {
+            float scale;
+            ctx->dct_coder[i].quality = quality;
+            if (quality > 50)
+                scale = 200.0f - 2 * quality;
+            else
+                scale = 5000.0f / quality;
+            gen_quant_mat(ctx->dct_coder[i].qmat,
+                          i ? mss3_chroma_quant : mss3_luma_quant,
+                          scale);
+        }
+        memset(ctx->dct_coder[i].prev_dc, 0,
+               sizeof(*ctx->dct_coder[i].prev_dc) *
+               ctx->dct_coder[i].prev_dc_stride *
+               ctx->dct_coder[i].prev_dc_height);
+        model_reset(&ctx->dct_coder[i].dc_model);
+        model2_reset(&ctx->dct_coder[i].sign_model);
+        model256_reset(&ctx->dct_coder[i].ac_model);
+        if (ctx->haar_coder[i].quality != quality) {
+            ctx->haar_coder[i].quality = quality;
+            ctx->haar_coder[i].scale   = 17 - 7 * quality / 50;
+        }
+        model_reset(&ctx->haar_coder[i].coef_hi_model);
+        model256_reset(&ctx->haar_coder[i].coef_model);
+    }
+}
+
+static av_cold void init_coders(MSS3Context *ctx)
+{
+    int i, j;
+
+    for (i = 0; i < 3; i++) {
+        for (j = 0; j < 5; j++)
+            model_init(&ctx->btype[i].bt_model[j], 5);
+        model_init(&ctx->fill_coder[i].coef_model, 12);
+        model256_init(&ctx->image_coder[i].esc_model);
+        model256_init(&ctx->image_coder[i].vec_entry_model);
+        model_init(&ctx->image_coder[i].vec_size_model, 3);
+        for (j = 0; j < 125; j++)
+            model_init(&ctx->image_coder[i].vq_model[j], 5);
+        model_init(&ctx->dct_coder[i].dc_model, 12);
+        model256_init(&ctx->dct_coder[i].ac_model);
+        model_init(&ctx->haar_coder[i].coef_hi_model, 12);
+        model256_init(&ctx->haar_coder[i].coef_model);
+    }
+}
+
+static int mss3_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
+                             AVPacket *avpkt)
+{
+    const uint8_t *buf = avpkt->data;
+    int buf_size = avpkt->size;
+    MSS3Context *c = avctx->priv_data;
+    RangeCoder *acoder = &c->coder;
+    GetByteContext gb;
+    uint8_t *dst[3];
+    int dec_width, dec_height, dec_x, dec_y, quality, keyframe;
+    int x, y, i, mb_width, mb_height, blk_size, btype;
+    int ret;
+
+    if (buf_size < HEADER_SIZE) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Frame should have at least %d bytes, got %d instead\n",
+               HEADER_SIZE, buf_size);
+        return AVERROR_INVALIDDATA;
+    }
+
+    bytestream2_init(&gb, buf, buf_size);
+    keyframe   = bytestream2_get_be32(&gb);
+    if (keyframe & ~0x301) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid frame type %X\n", keyframe);
+        return AVERROR_INVALIDDATA;
+    }
+    keyframe   = !(keyframe & 1);
+    bytestream2_skip(&gb, 6);
+    dec_x      = bytestream2_get_be16(&gb);
+    dec_y      = bytestream2_get_be16(&gb);
+    dec_width  = bytestream2_get_be16(&gb);
+    dec_height = bytestream2_get_be16(&gb);
+
+    if (dec_x + dec_width > avctx->width ||
+        dec_y + dec_height > avctx->height ||
+        (dec_width | dec_height) & 0xF) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid frame dimensions %dx%d +%d,%d\n",
+               dec_width, dec_height, dec_x, dec_y);
+        return AVERROR_INVALIDDATA;
+    }
+    bytestream2_skip(&gb, 4);
+    quality    = bytestream2_get_byte(&gb);
+    if (quality < 1 || quality > 100) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid quality setting %d\n", quality);
+        return AVERROR_INVALIDDATA;
+    }
+    bytestream2_skip(&gb, 4);
+
+    if (keyframe && !bytestream2_get_bytes_left(&gb)) {
+        av_log(avctx, AV_LOG_ERROR, "Keyframe without data found\n");
+        return AVERROR_INVALIDDATA;
+    }
+    if (!keyframe && c->got_error)
+        return buf_size;
+    c->got_error = 0;
+
+    c->pic.reference    = 3;
+    c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE |
+                          FF_BUFFER_HINTS_REUSABLE;
+    if ((ret = avctx->reget_buffer(avctx, &c->pic)) < 0) {
+        av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+        return ret;
+    }
+    c->pic.key_frame = keyframe;
+    c->pic.pict_type = keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+    if (!bytestream2_get_bytes_left(&gb)) {
+        *data_size = sizeof(AVFrame);
+        *(AVFrame*)data = c->pic;
+
+        return buf_size;
+    }
+
+    reset_coders(c, quality);
+
+    rac_init(acoder, buf + HEADER_SIZE, buf_size - HEADER_SIZE);
+
+    mb_width  = dec_width  >> 4;
+    mb_height = dec_height >> 4;
+    dst[0] = c->pic.data[0] + dec_x     +  dec_y      * c->pic.linesize[0];
+    dst[1] = c->pic.data[1] + dec_x / 2 + (dec_y / 2) * c->pic.linesize[1];
+    dst[2] = c->pic.data[2] + dec_x / 2 + (dec_y / 2) * c->pic.linesize[2];
+    for (y = 0; y < mb_height; y++) {
+        for (x = 0; x < mb_width; x++) {
+            for (i = 0; i < 3; i++) {
+                blk_size = 8 << !i;
+
+                btype = decode_block_type(acoder, c->btype + i);
+                switch (btype) {
+                case FILL_BLOCK:
+                    decode_fill_block(acoder, c->fill_coder + i,
+                                      dst[i] + x * blk_size,
+                                      c->pic.linesize[i], blk_size);
+                    break;
+                case IMAGE_BLOCK:
+                    decode_image_block(acoder, c->image_coder + i,
+                                       dst[i] + x * blk_size,
+                                       c->pic.linesize[i], blk_size);
+                    break;
+                case DCT_BLOCK:
+                    decode_dct_block(acoder, c->dct_coder + i,
+                                     dst[i] + x * blk_size,
+                                     c->pic.linesize[i], blk_size,
+                                     c->dctblock, x, y);
+                    break;
+                case HAAR_BLOCK:
+                    decode_haar_block(acoder, c->haar_coder + i,
+                                      dst[i] + x * blk_size,
+                                      c->pic.linesize[i], blk_size,
+                                      c->hblock);
+                    break;
+                }
+                if (c->got_error || acoder->got_error) {
+                    av_log(avctx, AV_LOG_ERROR, "Error decoding block %d,%d\n",
+                           x, y);
+                    c->got_error = 1;
+                    return AVERROR_INVALIDDATA;
+                }
+            }
+        }
+        dst[0] += c->pic.linesize[0] * 16;
+        dst[1] += c->pic.linesize[1] * 8;
+        dst[2] += c->pic.linesize[2] * 8;
+    }
+
+    *data_size = sizeof(AVFrame);
+    *(AVFrame*)data = c->pic;
+
+    return buf_size;
+}
+
+static av_cold int mss3_decode_init(AVCodecContext *avctx)
+{
+    MSS3Context * const c = avctx->priv_data;
+    int i;
+
+    c->avctx = avctx;
+
+    if ((avctx->width & 0xF) || (avctx->height & 0xF)) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Image dimensions should be multiple of 16\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    c->got_error = 0;
+    for (i = 0; i < 3; i++) {
+        int b_width  = avctx->width  >> (2 + !!i);
+        int b_height = avctx->height >> (2 + !!i);
+        c->dct_coder[i].prev_dc_stride = b_width;
+        c->dct_coder[i].prev_dc_height = b_height;
+        c->dct_coder[i].prev_dc = av_malloc(sizeof(*c->dct_coder[i].prev_dc) *
+                                            b_width * b_height);
+        if (!c->dct_coder[i].prev_dc) {
+            av_log(avctx, AV_LOG_ERROR, "Cannot allocate buffer\n");
+            while (i >= 0) {
+                av_freep(&c->dct_coder[i].prev_dc);
+                i--;
+            }
+            return AVERROR(ENOMEM);
+        }
+    }
+
+    avctx->pix_fmt = PIX_FMT_YUV420P;
+
+    avctx->coded_frame = &c->pic;
+
+    init_coders(c);
+
+    return 0;
+}
+
+static av_cold int mss3_decode_end(AVCodecContext *avctx)
+{
+    MSS3Context * const c = avctx->priv_data;
+    int i;
+
+    if (c->pic.data[0])
+        avctx->release_buffer(avctx, &c->pic);
+    for (i = 0; i < 3; i++)
+        av_freep(&c->dct_coder[i].prev_dc);
+
+    return 0;
+}
+
+AVCodec ff_msa1_decoder = {
+    .name           = "msa1",
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = CODEC_ID_MSA1,
+    .priv_data_size = sizeof(MSS3Context),
+    .init           = mss3_decode_init,
+    .close          = mss3_decode_end,
+    .decode         = mss3_decode_frame,
+    .capabilities   = CODEC_CAP_DR1,
+    .long_name      = NULL_IF_CONFIG_SMALL("MS ATC Screen"),
+};
diff --git a/libavformat/riff.c b/libavformat/riff.c
index efab704..0aef2d7 100644
--- a/libavformat/riff.c
+++ b/libavformat/riff.c
@@ -285,6 +285,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
     { CODEC_ID_DXTORY,       MKTAG('x', 't', 'o', 'r') },
     { CODEC_ID_ZEROCODEC,    MKTAG('Z', 'E', 'C', 'O') },
     { CODEC_ID_MSS1,         MKTAG('M', 'S', 'S', '1') },
+    { CODEC_ID_MSA1,         MKTAG('M', 'S', 'A', '1') },
     { CODEC_ID_NONE,         0 }
 };
 
-- 
1.7.0.4

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

Reply via email to