On 13/09/13 22:31, Justin Ruggles wrote:
> ---
>  doc/general.texi  |    2 +-
>  libavcodec/webp.c | 1173 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 1164 insertions(+), 11 deletions(-)
> 
> diff --git a/doc/general.texi b/doc/general.texi
> index 18e425a..aeda8ea 100644
> --- a/doc/general.texi
> +++ b/doc/general.texi
> @@ -413,7 +413,7 @@ following image formats are supported:
>  @item Truevision Targa  @tab X @tab X
>      @tab Targa (.TGA) image format
>  @item WebP         @tab @tab X
> -    @tab WebP image format (lossy only)
> +    @tab WebP image format
>  @item XBM  @tab X @tab
>      @tab X BitMap image format
>  @item XWD  @tab X @tab X
> diff --git a/libavcodec/webp.c b/libavcodec/webp.c
> index 33b242f..04313b4 100644
> --- a/libavcodec/webp.c
> +++ b/libavcodec/webp.c
> @@ -1,6 +1,7 @@
>  /*
>   * WebP (.webp) image decoder
>   * Copyright (c) 2013 Aneesh Dogra <[email protected]>
> + * Copyright (c) 2013 Justin Ruggles <[email protected]>
>   *
>   * This file is part of Libav.
>   *
> @@ -19,9 +20,11 @@
>   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
> USA
>   */
>  
> +#define BITSTREAM_READER_LE
>  #include "avcodec.h"
>  #include "bytestream.h"
>  #include "internal.h"
> +#include "get_bits.h"
>  #include "vp8.h"
>  
>  #define VP8X_FLAG_ANIMATION     0x2
> @@ -30,33 +33,1164 @@
>  #define VP8X_FLAG_ALPHA         0x10
>  #define VP8X_FLAG_ICC           0x20
>  
> +#define MAX_PALETTE_SIZE                256
> +#define MAX_CACHE_BITS                  11
> +#define NUM_CODE_LENGTH_CODES           19
> +#define HUFFMAN_CODES_PER_META_CODE     5
> +#define NUM_LITERAL_CODES               256
> +#define NUM_LENGTH_CODES                24
> +#define NUM_DISTANCE_CODES              40
> +#define NUM_SHORT_DISTANCES             120
> +#define MAX_HUFFMAN_CODE_LENGTH         15

While at it maybe sort them so NUM and MAX aren't mixed randomly.

> +
> +static const uint16_t alphabet_sizes[HUFFMAN_CODES_PER_META_CODE] = {
> +    NUM_LITERAL_CODES + NUM_LENGTH_CODES,
> +    NUM_LITERAL_CODES, NUM_LITERAL_CODES, NUM_LITERAL_CODES,
> +    NUM_DISTANCE_CODES
> +};
> +
> +static const uint8_t code_length_code_order[NUM_CODE_LENGTH_CODES] = {
> +    17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
> +};
> +
> +static const int8_t lz77_distance_offsets[NUM_SHORT_DISTANCES][2] = {
> +    {  0, 1 }, {  1, 0 }, {  1, 1 }, { -1, 1 }, {  0, 2 }, {  2, 0 }, {  1, 
> 2 }, { -1, 2 },
> +    {  2, 1 }, { -2, 1 }, {  2, 2 }, { -2, 2 }, {  0, 3 }, {  3, 0 }, {  1, 
> 3 }, { -1, 3 },
> +    {  3, 1 }, { -3, 1 }, {  2, 3 }, { -2, 3 }, {  3, 2 }, { -3, 2 }, {  0, 
> 4 }, {  4, 0 },
> +    {  1, 4 }, { -1, 4 }, {  4, 1 }, { -4, 1 }, {  3, 3 }, { -3, 3 }, {  2, 
> 4 }, { -2, 4 },
> +    {  4, 2 }, { -4, 2 }, {  0, 5 }, {  3, 4 }, { -3, 4 }, {  4, 3 }, { -4, 
> 3 }, {  5, 0 },
> +    {  1, 5 }, { -1, 5 }, {  5, 1 }, { -5, 1 }, {  2, 5 }, { -2, 5 }, {  5, 
> 2 }, { -5, 2 },
> +    {  4, 4 }, { -4, 4 }, {  3, 5 }, { -3, 5 }, {  5, 3 }, { -5, 3 }, {  0, 
> 6 }, {  6, 0 },
> +    {  1, 6 }, { -1, 6 }, {  6, 1 }, { -6, 1 }, {  2, 6 }, { -2, 6 }, {  6, 
> 2 }, { -6, 2 },
> +    {  4, 5 }, { -4, 5 }, {  5, 4 }, { -5, 4 }, {  3, 6 }, { -3, 6 }, {  6, 
> 3 }, { -6, 3 },
> +    {  0, 7 }, {  7, 0 }, {  1, 7 }, { -1, 7 }, {  5, 5 }, { -5, 5 }, {  7, 
> 1 }, { -7, 1 },
> +    {  4, 6 }, { -4, 6 }, {  6, 4 }, { -6, 4 }, {  2, 7 }, { -2, 7 }, {  7, 
> 2 }, { -7, 2 },
> +    {  3, 7 }, { -3, 7 }, {  7, 3 }, { -7, 3 }, {  5, 6 }, { -5, 6 }, {  6, 
> 5 }, { -6, 5 },
> +    {  8, 0 }, {  4, 7 }, { -4, 7 }, {  7, 4 }, { -7, 4 }, {  8, 1 }, {  8, 
> 2 }, {  6, 6 },
> +    { -6, 6 }, {  8, 3 }, {  5, 7 }, { -5, 7 }, {  7, 5 }, { -7, 5 }, {  8, 
> 4 }, {  6, 7 },
> +    { -6, 7 }, {  7, 6 }, { -7, 6 }, {  8, 5 }, {  7, 7 }, { -7, 7 }, {  8, 
> 6 }, {  8, 7 }
> +};
> +
> +enum TransformType {
> +    PREDICTOR_TRANSFORM      = 0,
> +    COLOR_TRANSFORM          = 1,
> +    SUBTRACT_GREEN           = 2,
> +    COLOR_INDEXING_TRANSFORM = 3,
> +};
> +
> +enum PredictionMode {
> +    PRED_MODE_BLACK,
> +    PRED_MODE_L,
> +    PRED_MODE_T,
> +    PRED_MODE_TR,
> +    PRED_MODE_TL,
> +    PRED_MODE_AVG_T_AVG_L_TR,
> +    PRED_MODE_AVG_L_TL,
> +    PRED_MODE_AVG_L_T,
> +    PRED_MODE_AVG_TL_T,
> +    PRED_MODE_AVG_T_TR,
> +    PRED_MODE_AVG_AVG_L_TL_AVG_T_TR,
> +    PRED_MODE_SELECT,
> +    PRED_MODE_ADD_SUBTRACT_FULL,
> +    PRED_MODE_ADD_SUBTRACT_HALF,
> +};
> +
> +enum HuffmanIndex {
> +    HUFF_IDX_GREEN = 0,
> +    HUFF_IDX_RED   = 1,
> +    HUFF_IDX_BLUE  = 2,
> +    HUFF_IDX_ALPHA = 3,
> +    HUFF_IDX_DIST  = 4
> +};
> +
> +enum ImageRole {
> +    /* Stores the actual pixels of the image. */
> +    IMAGE_ROLE_ARGB,
> +
> +    /* Stores the meta Huffman codes. The red and green components of a pixel
> +       define the meta Huffman code used in a particular block of the ARGB
> +       image. */
> +    IMAGE_ROLE_ENTROPY,
> +
> +    /* Stores the metadata for Predictor Transform. The green component of a
> +       pixel defines which of the 14 predictors is used within a particular
> +       block of the ARGB image. */
> +    IMAGE_ROLE_PREDICTOR,
> +
> +    /* It is created by ColorTransformElement values for different blocks of
> +       the image. Each ColorTransformElement is treated as a pixel whose 
> alpha
> +       component is 255, red component is cte.red_to_blue, green component is
> +       cte.green_to_blue and blue component is cte.green_to_red. */
> +    IMAGE_ROLE_COLOR_TRANSFORM,
> +
> +    /* Color indexing image: An array of of size color_table_size (up to 256
> +       ARGB values) storing the metadata for the Color Indexing Transform. 
> This
> +       is stored as an image of width color_table_size and height 1. */
> +    IMAGE_ROLE_COLOR_INDEXING,
> +
> +    IMAGE_ROLE_NB,
> +};
> +
> +typedef struct HuffReader {
> +    VLC vlc;
> +    int simple;
> +    int nb_symbols;
> +    uint16_t simple_symbols[2];
> +} HuffReader;
> +
> +typedef struct HuffmanGroup {
> +    HuffReader huffman_code[HUFFMAN_CODES_PER_META_CODE];
> +} HuffmanGroup;

Why?

> +typedef struct ImageContext {
> +    enum ImageRole role;
> +    AVFrame *frame;
> +    int color_cache_bits;
> +    uint8_t *color_cache;
> +    int num_huffman_groups;
> +    HuffmanGroup *huffman_groups;
> +} ImageContext;
> +
> +typedef union {
> +    uint8_t u8;
> +    int8_t  s8;
> +} av_alias alias8;

Don't we have something like this in avutils?

> +
>  typedef struct WebPContext {
>      VP8Context v;
> +    AVCodecContext *avctx;
>      int initialized;
> +    GetBitContext gb;
>      GetByteContext alpha_gb;
>      uint8_t has_alpha;
>      int width;
>      int height;
> +
> +    int lossless;
> +    ImageContext image[IMAGE_ROLE_NB];
> +    enum TransformType transforms[4];
> +    int nb_transforms;
> +    int subtract_green;
> +    int predictor_block_size;
> +    int color_block_size;
> +    int color_index_width_bits;
> +    int reduced_width;
> +    int use_entropy_image;
> +    int entropy_size;
>  } WebPContext;
>  
> +static av_always_inline uint8_t *get_pixel(AVFrame *frame, int x, int y)
> +{
> +    if (x < 0 || y < 0)
> +        return NULL;
> +    if (x >= frame->width) {
> +        x = 0;
> +        y++;
> +    }
> +    if (y >= frame->height)
> +        return NULL;
> +
> +    return frame->data[0] + y * frame->linesize[0] + 4 * x;
> +}
> +
> +static av_always_inline uint8_t add_comp(int a, int b)
> +{
> +    return (a + b) & 0xFF;
> +}
> +
> +static av_always_inline uint8_t avg2_comp(int a, int b)
> +{
> +    return (a + b) / 2;
> +}
> +
> +static av_always_inline uint8_t clamp_add_subtract_full(int a, int b, int c)
> +{
> +    return av_clip_uint8(a + b - c);
> +}
> +
> +static av_always_inline uint8_t clamp_add_subtract_half(int a, int b, int c)
> +{
> +    int d = avg2_comp(a, b);
> +    return av_clip_uint8(d + (d - c) / 2);
> +}

Some of those above should be in avutil already.

> +static void image_ctx_free(ImageContext *img)
> +{
> +    int i, j;
> +
> +    if (img->color_cache)
> +        av_free(img->color_cache);
> +    if (img->role != IMAGE_ROLE_ARGB)
> +        av_frame_free(&img->frame);
> +    if (img->huffman_groups && img->num_huffman_groups > 0) {
> +        for (i = 0; i < img->num_huffman_groups; i++) {
> +            for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; j++) {
> +                if (!img->huffman_groups[i].huffman_code[j].simple)
> +                    ff_free_vlc(&img->huffman_groups[i].huffman_code[j].vlc);
> +            }
> +        }
> +        av_free(img->huffman_groups);
> +    }
> +    memset(img, 0, sizeof(*img));
> +}
> +
> +
> +/* Differs from get_vlc2() in the following ways:
> + *   - codes are bit-reversed
> + *   - assumes 8-bit table to make reversal simpler
> + *   - assumes max depth of 2 since the max code length for WebP is 15
> + */
> +static av_always_inline int webp_get_vlc(GetBitContext *gb, VLC_TYPE 
> (*table)[2])
> +{
> +    int n, nb_bits;
> +    unsigned int index;
> +    int code;
> +
> +    OPEN_READER(re, gb);
> +    UPDATE_CACHE(re, gb);
> +
> +    index = SHOW_UBITS(re, gb, 8);
> +    index = ff_reverse[index];
> +    code  = table[index][0];
> +    n     = table[index][1];
> +
> +    if (n < 0) {
> +        LAST_SKIP_BITS(re, gb, 8);
> +        UPDATE_CACHE(re, gb);
> +
> +        nb_bits = -n;
> +
> +        index = SHOW_UBITS(re, gb, nb_bits);
> +        index = (ff_reverse[index] >> (8 - nb_bits)) + code;
> +        code  = table[index][0];
> +        n     = table[index][1];
> +    }
> +    SKIP_BITS(re, gb, n);
> +
> +    CLOSE_READER(re, gb);
> +
> +    return code;
> +}
> +
> +static int huff_reader_get_symbol(HuffReader *r, GetBitContext *gb)
> +{
> +    if (!r->nb_symbols)
> +        return AVERROR_BUG;
> +
> +    if (r->simple) {
> +        if (r->nb_symbols == 1) {
> +            return r->simple_symbols[0];
> +        } else {
> +            return r->simple_symbols[get_bits1(gb)];
> +        }
> +    } else {
> +        return webp_get_vlc(gb, r->vlc.table);
> +    }
> +}
> +
> +static int huff_reader_build_canonical(HuffReader *r, int *code_lengths,
> +                                       int alphabet_size)
> +{
> +    int len, sym, code;
> +    int max_code_length = 0;
> +    uint16_t *codes;
> +
> +    for (sym = 0; sym < alphabet_size; sym++)
> +        max_code_length = FFMAX(max_code_length, code_lengths[sym]);
> +
> +    if (max_code_length == 0 || max_code_length > MAX_HUFFMAN_CODE_LENGTH)
> +        return AVERROR(EINVAL);
> +
> +    codes = av_malloc(alphabet_size * sizeof(*codes));
> +    if (!codes)
> +        return AVERROR(ENOMEM);
> +
> +    code = 0;
> +    r->nb_symbols = 0;
> +    for (len = 1; len <= max_code_length; len++) {
> +        for (sym = 0; sym < alphabet_size; sym++) {
> +            if (code_lengths[sym] != len)
> +                continue;
> +            codes[sym] = code++;
> +            r->nb_symbols++;
> +        }
> +        code <<= 1;
> +    }
> +
> +    init_vlc(&r->vlc, 8, alphabet_size,
> +             code_lengths, sizeof(*code_lengths), sizeof(*code_lengths),
> +             codes, sizeof(*codes), sizeof(*codes), 0);
> +    r->simple = 0;
> +
> +    av_free(codes);
> +    return 0;
> +}
> +
> +static void read_huffman_code_simple(WebPContext *s, HuffReader *hc)
> +{
> +    hc->nb_symbols = get_bits1(&s->gb) + 1;
> +
> +    if (get_bits1(&s->gb))
> +        hc->simple_symbols[0] = get_bits(&s->gb, 8);
> +    else
> +        hc->simple_symbols[0] = get_bits1(&s->gb);
> +
> +    if (hc->nb_symbols == 2) {
> +        hc->simple_symbols[1] = get_bits(&s->gb, 8);
> +    }
> +    hc->simple = 1;
> +}
> +
> +static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
> +                                    int alphabet_size)
> +{
> +    HuffReader code_len_hc;
> +    int *code_lengths = NULL;
> +    int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
> +    int i, symbol, max_symbol, prev_code_len, ret = 0;
> +    int num_codes = 4 + get_bits(&s->gb, 4);
> +
> +    if (num_codes > NUM_CODE_LENGTH_CODES)
> +        return AVERROR_INVALIDDATA;
> +
> +    for (i = 0; i < num_codes; i++)
> +        code_length_code_lengths[code_length_code_order[i]] = 
> get_bits(&s->gb, 3);
> +
> +    memset(&code_len_hc, 0, sizeof(code_len_hc));
> +    ret = huff_reader_build_canonical(&code_len_hc, code_length_code_lengths,
> +                                      NUM_CODE_LENGTH_CODES);
> +    if (ret < 0)
> +        goto finish;
> +
> +    code_lengths = av_mallocz_array(alphabet_size, sizeof(*code_lengths));
> +    if (!code_lengths) {
> +        ret = AVERROR(ENOMEM);
> +        goto finish;
> +    }
> +
> +    if (get_bits1(&s->gb)) {
> +        int bits   = 2 + 2 * get_bits(&s->gb, 3);
> +        max_symbol = 2 + get_bits(&s->gb, bits);
> +        if (max_symbol > alphabet_size) {
> +            av_log(s->avctx, AV_LOG_ERROR, "max symbol %d > alphabet size 
> %d\n",
> +                   max_symbol, alphabet_size);
> +            ret = AVERROR_INVALIDDATA;
> +            goto finish;
> +        }
> +    } else {
> +        max_symbol = alphabet_size;
> +    }
> +
> +    prev_code_len = 8;
> +    symbol = 0;
> +    while (symbol < alphabet_size) {
> +        int code_len;
> +
> +        if (!max_symbol--)
> +            break;
> +        code_len = huff_reader_get_symbol(&code_len_hc, &s->gb);
> +        if (code_len < 16) {
> +            /* Code length code [0..15] indicates literal code lengths. */
> +            code_lengths[symbol++] = code_len;
> +            if (code_len)
> +                prev_code_len = code_len;
> +        } else {
> +            int repeat = 0, length = 0;
> +            if (code_len == 16) {
> +                /* Code 16 repeats the previous non-zero value [3..6] times,
> +                   i.e., 3 + ReadBits(2) times. If code 16 is used before a
> +                   non-zero value has been emitted, a value of 8 is 
> repeated. */
> +                repeat = 3 + get_bits(&s->gb, 2);
> +                length = prev_code_len;
> +            } else if (code_len == 17) {
> +                /* Code 17 emits a streak of zeros [3..10], i.e.,
> +                   3 + ReadBits(3) times. */
> +                repeat = 3 + get_bits(&s->gb, 3);
> +            } else if (code_len == 18) {
> +                /* Code 18 emits a streak of zeros of length [11..138], i.e.,
> +                   11 + ReadBits(7) times. */
> +                repeat = 11 + get_bits(&s->gb, 7);
> +            }
> +            if (symbol + repeat > alphabet_size) {
> +                av_log(s->avctx, AV_LOG_ERROR,
> +                       "invalid symbol %d + repeat %d > alphabet size %d\n",
> +                       symbol, repeat, alphabet_size);
> +                ret = AVERROR_INVALIDDATA;
> +                goto finish;
> +            }
> +            while (repeat-- > 0)
> +                code_lengths[symbol++] = length;
> +        }
> +    }
> +
> +    ret = huff_reader_build_canonical(hc, code_lengths, alphabet_size);
> +
> +finish:
> +    ff_free_vlc(&code_len_hc.vlc);
> +    av_free(code_lengths);
> +    return ret;
> +}
> +
> +static int decode_entropy_coded_image(WebPContext *s, enum ImageRole role);
> +
> +static int decode_image(WebPContext *s, enum ImageRole role, int w, int h)
> +{
> +    ImageContext *img;
> +    int ret;
> +
> +    img       = &s->image[role];
> +    img->role = role;
> +
> +    img->frame = av_frame_alloc();
> +    if (!img->frame)
> +        return AVERROR(ENOMEM);
> +
> +    img->frame->format = AV_PIX_FMT_ARGB;
> +    img->frame->width  = w;
> +    img->frame->height = h;
> +
> +    ret = av_frame_get_buffer(img->frame, 1);
> +    if (ret < 0) {
> +        av_frame_free(&img->frame);
> +        return ret;
> +    }
> +
> +    ret = decode_entropy_coded_image(s, img->role);
> +    if (ret < 0) {
> +        av_frame_free(&img->frame);
> +        return ret;
> +    }
> +
> +    return 0;
> +}
> +
> +#define PARSE_BLOCK_SIZE(w, h) do {                                         \
> +    block_bits = get_bits(&s->gb, 3) + 2;                                   \
> +    block_size = 1 << block_bits;                                           \
> +    blocks_w   = FFALIGN((w), block_size) / block_size;                     \
> +    blocks_h   = FFALIGN((h), block_size) / block_size;                     \
> +} while (0)
> +
> +static int decode_entropy_image(WebPContext *s, ImageContext *rgba_img)
> +{
> +    int ret, block_bits, block_size, width, blocks_w, blocks_h;
> +
> +    width = s->width;
> +    if (s->color_index_width_bits > 0)
> +        width = s->reduced_width;
> +
> +    PARSE_BLOCK_SIZE(width, s->height);
> +
> +    ret = decode_image(s, IMAGE_ROLE_ENTROPY, blocks_w, blocks_h);
> +    if (ret < 0)
> +        return ret;
> +
> +    s->use_entropy_image = 1;
> +    s->entropy_size      = block_size;
> +
> +    /* the number of huffman groups is determined by the maximum group number
> +       coded in the entropy image */
> +    {
> +        ImageContext *img;
> +        int x, y, max;
> +        uint8_t *p;
> +
> +        img = &s->image[IMAGE_ROLE_ENTROPY];
> +        max = 0;
> +        for (y = 0; y < img->frame->height; y++) {
> +            for (x = 0; x < img->frame->width; x++) {
> +                p = get_pixel(img->frame, x, y);
> +                max = FFMAX(max, p[2]);
> +            }
> +        }
> +        rgba_img->num_huffman_groups = max + 1;
> +    }
> +
> +    return 0;
> +}
> +
> +static int parse_transform_predictor(WebPContext *s)
> +{
> +    int block_bits, block_size, blocks_w, blocks_h, ret;
> +
> +    PARSE_BLOCK_SIZE(s->width, s->height);
> +
> +    ret = decode_image(s, IMAGE_ROLE_PREDICTOR, blocks_w, blocks_h);
> +    if (ret < 0)
> +        return ret;
> +
> +    s->predictor_block_size = block_size;
> +
> +    return 0;
> +}
> +
> +static int parse_transform_color(WebPContext *s)
> +{
> +    int block_bits, block_size, blocks_w, blocks_h, ret;
> +
> +    PARSE_BLOCK_SIZE(s->width, s->height);
> +
> +    ret = decode_image(s, IMAGE_ROLE_COLOR_TRANSFORM, blocks_w, blocks_h);
> +    if (ret < 0)
> +        return ret;
> +
> +    s->color_block_size = block_size;
> +
> +    return 0;
> +}
> +
> +static int parse_transform_color_indexing(WebPContext *s)
> +{
> +    int width_bits, index_size, ret;
> +
> +    index_size = get_bits(&s->gb, 8) + 1;
> +
> +    if (index_size <= 2)
> +        width_bits = 3;
> +    else if (index_size <= 4)
> +        width_bits = 2;
> +    else if (index_size <= 16)
> +        width_bits = 1;
> +    else
> +        width_bits = 0;
> +
> +    ret = decode_image(s, IMAGE_ROLE_COLOR_INDEXING, index_size, 1);
> +    if (ret < 0)
> +        return ret;
> +
> +    s->color_index_width_bits = width_bits;
> +    if (width_bits > 0)
> +        s->reduced_width = (s->width + ((1 << width_bits) - 1)) >> 
> width_bits;
> +
> +    /* color index values are delta-coded */
> +    {
> +        ImageContext *img;
> +        int x;
> +        uint8_t *ct, *ct0 = NULL;
> +
> +        img = &s->image[IMAGE_ROLE_COLOR_INDEXING];
> +        ct  = img->frame->data[0];
> +        for (x = 0; x < img->frame->width; x++) {
> +            if (ct0) {
> +                ct[0] = add_comp(ct[0], ct0[0]);
> +                ct[1] = add_comp(ct[1], ct0[1]);
> +                ct[2] = add_comp(ct[2], ct0[2]);
> +                ct[3] = add_comp(ct[3], ct0[3]);
> +            }
> +            ct0 = ct;
> +            ct += 4;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static HuffmanGroup *get_huffman_group(WebPContext *s, ImageContext *img,
> +                                       int x, int y)
> +{
> +    ImageContext *gimg = &s->image[IMAGE_ROLE_ENTROPY];
> +    int group = 0;
> +    uint8_t *p;
> +
> +    if (s->use_entropy_image) {
> +        int group_x, group_y;
> +
> +        group_x = x / s->entropy_size;
> +        group_y = y / s->entropy_size;
> +        p = get_pixel(gimg->frame, group_x, group_y);
> +        group = p[2];
> +    }
> +
> +    return &img->huffman_groups[group];
> +}
> +
> +/* PRED_MODE_BLACK */
> +static void inv_predict_0(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                          const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    static const uint8_t black[4] = { 0xFF, 0x00, 0x00, 0x00 };
> +
> +    AV_COPY32(p, black);
> +}
> +
> +/* PRED_MODE_L */
> +static void inv_predict_1(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                          const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    AV_COPY32(p, p_l);
> +}
> +
> +/* PRED_MODE_T */
> +static void inv_predict_2(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                          const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    AV_COPY32(p, p_t);
> +}
> +
> +/* PRED_MODE_TR */
> +static void inv_predict_3(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                          const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    AV_COPY32(p, p_tr);
> +}
> +
> +/* PRED_MODE_TL */
> +static void inv_predict_4(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                          const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    AV_COPY32(p, p_tl);
> +}
> +
> +/* PRED_MODE_AVG_T_AVG_L_TR */
> +static void inv_predict_5(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                          const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    p[0] = avg2_comp(p_t[0], avg2_comp(p_l[0], p_tr[0]));
> +    p[1] = avg2_comp(p_t[1], avg2_comp(p_l[1], p_tr[1]));
> +    p[2] = avg2_comp(p_t[2], avg2_comp(p_l[2], p_tr[2]));
> +    p[3] = avg2_comp(p_t[3], avg2_comp(p_l[3], p_tr[3]));
> +}
> +
> +/* PRED_MODE_AVG_L_TL */
> +static void inv_predict_6(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                          const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    p[0] = avg2_comp(p_l[0], p_tl[0]);
> +    p[1] = avg2_comp(p_l[1], p_tl[1]);
> +    p[2] = avg2_comp(p_l[2], p_tl[2]);
> +    p[3] = avg2_comp(p_l[3], p_tl[3]);
> +}
> +
> +/* PRED_MODE_AVG_L_T */
> +static void inv_predict_7(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                          const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    p[0] = avg2_comp(p_l[0], p_t[0]);
> +    p[1] = avg2_comp(p_l[1], p_t[1]);
> +    p[2] = avg2_comp(p_l[2], p_t[2]);
> +    p[3] = avg2_comp(p_l[3], p_t[3]);
> +}
> +
> +/* PRED_MODE_AVG_TL_T */
> +static void inv_predict_8(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                          const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    p[0] = avg2_comp(p_tl[0], p_t[0]);
> +    p[1] = avg2_comp(p_tl[1], p_t[1]);
> +    p[2] = avg2_comp(p_tl[2], p_t[2]);
> +    p[3] = avg2_comp(p_tl[3], p_t[3]);
> +}
> +
> +/* PRED_MODE_AVG_T_TR */
> +static void inv_predict_9(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                          const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    p[0] = avg2_comp(p_t[0], p_tr[0]);
> +    p[1] = avg2_comp(p_t[1], p_tr[1]);
> +    p[2] = avg2_comp(p_t[2], p_tr[2]);
> +    p[3] = avg2_comp(p_t[3], p_tr[3]);
> +}
> +
> +/* PRED_MODE_AVG_AVG_L_TL_AVG_T_TR */
> +static void inv_predict_10(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                           const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    p[0] = avg2_comp(avg2_comp(p_l[0], p_tl[0]), avg2_comp(p_t[0], p_tr[0]));
> +    p[1] = avg2_comp(avg2_comp(p_l[1], p_tl[1]), avg2_comp(p_t[1], p_tr[1]));
> +    p[2] = avg2_comp(avg2_comp(p_l[2], p_tl[2]), avg2_comp(p_t[2], p_tr[2]));
> +    p[3] = avg2_comp(avg2_comp(p_l[3], p_tl[3]), avg2_comp(p_t[3], p_tr[3]));
> +}
> +
> +/* PRED_MODE_SELECT */
> +static void inv_predict_11(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                           const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    int diff = (abs(p_l[0] - p_tl[0]) - abs(p_t[0] - p_tl[0])) +
> +               (abs(p_l[1] - p_tl[1]) - abs(p_t[1] - p_tl[1])) +
> +               (abs(p_l[2] - p_tl[2]) - abs(p_t[2] - p_tl[2])) +
> +               (abs(p_l[3] - p_tl[3]) - abs(p_t[3] - p_tl[3]));
> +    if (diff <= 0)
> +        AV_COPY32(p, p_t);
> +    else
> +        AV_COPY32(p, p_l);
> +}
> +
> +/* PRED_MODE_ADD_SUBTRACT_FULL */
> +static void inv_predict_12(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                           const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    p[0] = clamp_add_subtract_full(p_l[0], p_t[0], p_tl[0]);
> +    p[1] = clamp_add_subtract_full(p_l[1], p_t[1], p_tl[1]);
> +    p[2] = clamp_add_subtract_full(p_l[2], p_t[2], p_tl[2]);
> +    p[3] = clamp_add_subtract_full(p_l[3], p_t[3], p_tl[3]);
> +}
> +
> +/* PRED_MODE_ADD_SUBTRACT_HALF */
> +static void inv_predict_13(uint8_t *p, const uint8_t *p_l, const uint8_t 
> *p_tl,
> +                           const uint8_t *p_t, const uint8_t *p_tr)
> +{
> +    p[0] = clamp_add_subtract_half(p_l[0], p_t[0], p_tl[0]);
> +    p[1] = clamp_add_subtract_half(p_l[1], p_t[1], p_tl[1]);
> +    p[2] = clamp_add_subtract_half(p_l[2], p_t[2], p_tl[2]);
> +    p[3] = clamp_add_subtract_half(p_l[3], p_t[3], p_tl[3]);
> +}
> +
> +typedef void (*inv_predict_func)(uint8_t *p, const uint8_t *p_l,
> +                                 const uint8_t *p_tl, const uint8_t *p_t,
> +                                 const uint8_t *p_tr);
> +
> +static const inv_predict_func inverse_predict[14] = {
> +    inv_predict_0,  inv_predict_1,  inv_predict_2,  inv_predict_3,
> +    inv_predict_4,  inv_predict_5,  inv_predict_6,  inv_predict_7,
> +    inv_predict_8,  inv_predict_9,  inv_predict_10, inv_predict_11,
> +    inv_predict_12, inv_predict_13,
> +};
> +
> +static void inverse_prediction(AVFrame *frame, enum PredictionMode m, int x, 
> int y)
> +{
> +    uint8_t *dec, *p_l, *p_tl, *p_t, *p_tr;
> +    uint8_t p[4];
> +
> +    dec  = get_pixel(frame, x,     y);
> +    p_l  = get_pixel(frame, x - 1, y);
> +    p_tl = get_pixel(frame, x - 1, y - 1);
> +    p_t  = get_pixel(frame, x,     y - 1);
> +    p_tr = get_pixel(frame, x + 1, y - 1);
> +
> +    inverse_predict[m](p, p_l, p_tl, p_t, p_tr);
> +
> +    dec[0] = add_comp(dec[0], p[0]);
> +    dec[1] = add_comp(dec[1], p[1]);
> +    dec[2] = add_comp(dec[2], p[2]);
> +    dec[3] = add_comp(dec[3], p[3]);
> +}
> +
> +static int apply_predictor_transform(WebPContext *s)
> +{
> +    ImageContext *img  = &s->image[IMAGE_ROLE_ARGB];
> +    ImageContext *pimg = &s->image[IMAGE_ROLE_PREDICTOR];
> +    int block_size     = s->predictor_block_size;
> +    int x, y;
> +
> +    for (y = 0; y < img->frame->height; y++) {
> +        for (x = 0; x < img->frame->width; x++) {
> +            int tx     = x / block_size;
> +            int ty     = y / block_size;
> +            uint8_t *p = get_pixel(pimg->frame, tx, ty);
> +            enum PredictionMode m = p[2];
> +
> +            if (x == 0) {
> +                if (y == 0)
> +                    m = PRED_MODE_BLACK;
> +                else
> +                    m = PRED_MODE_T;
> +            } else if (y == 0) {
> +                m = PRED_MODE_L;
> +            }
> +
> +            if (m > 13) {
> +                av_log(s->avctx, AV_LOG_ERROR, "invalid predictor mode: 
> %d\n", m);
> +                return AVERROR_INVALIDDATA;
> +            }
> +            inverse_prediction(img->frame, m, x, y);
> +        }
> +    }
> +    return 0;
> +}
> +
> +static av_always_inline int color_transform_delta(int color_pred, int color)
> +{
> +    return (color_pred * color) >> 5;
> +}
> +
> +static int apply_color_transform(WebPContext *s)
> +{
> +    ImageContext *img, *cimg;
> +    int x, y, cx, cy;
> +    uint8_t *p, *cp;
> +    int block_size = s->color_block_size;
> +
> +    img   = &s->image[IMAGE_ROLE_ARGB];
> +    cimg  = &s->image[IMAGE_ROLE_COLOR_TRANSFORM];
> +
> +    for (y = 0; y < img->frame->height; y++) {
> +        for (x = 0; x < img->frame->width; x++) {
> +            alias8 green_to_red, green_to_blue, red_to_blue;
> +            alias8 green, red;
> +            int blue;
> +
> +            cx = x / block_size;
> +            cy = y / block_size;
> +            cp = get_pixel(cimg->frame, cx, cy);
> +            red_to_blue.u8   = cp[1];
> +            green_to_blue.u8 = cp[2];
> +            green_to_red.u8  = cp[3];
> +
> +            p = get_pixel(img->frame, x, y);
> +            red.u8   = p[1];
> +            green.u8 = p[2];
> +            blue     = p[3];
> +
> +            red.u8 = add_comp(red.u8, color_transform_delta(green_to_red.s8, 
>  green.s8));
> +            blue  +=                  
> color_transform_delta(green_to_blue.s8, green.s8);
> +            blue   = add_comp(blue,   color_transform_delta(red_to_blue.s8,  
>  red.s8));
> +
> +            p[1]  = red.u8;
> +            p[3]  = blue;
> +        }
> +    }
> +    return 0;
> +}
> +
> +static int apply_subtract_green_transform(WebPContext *s)
> +{
> +    int x, y;
> +    ImageContext *img = &s->image[IMAGE_ROLE_ARGB];
> +
> +    for (y = 0; y < img->frame->height; y++) {
> +        for (x = 0; x < img->frame->width; x++) {
> +            uint8_t *p = get_pixel(img->frame, x, y);
> +            p[1] = add_comp(p[1], p[2]);
> +            p[3] = add_comp(p[3], p[2]);
> +        }
> +    }
> +    return 0;
> +}
> +
> +static int apply_color_indexing_transform(WebPContext *s)
> +{
> +    ImageContext *img;
> +    ImageContext *pal;
> +    int i, x, y;
> +    uint8_t *p, *pi;
> +    int width_bits = s->color_index_width_bits;
> +
> +    img = &s->image[IMAGE_ROLE_ARGB];
> +    pal = &s->image[IMAGE_ROLE_COLOR_INDEXING];
> +
> +    if (width_bits > 0) {
> +        GetBitContext gb_g;
> +        uint8_t *line;
> +        int pixel_bits = 8 >> width_bits;
> +
> +        line = av_malloc(img->frame->linesize[0]);
> +        if (!line)
> +            return AVERROR(ENOMEM);
> +
> +        for (y = 0; y < img->frame->height; y++) {
> +            p = get_pixel(img->frame, 0, y);
> +            memcpy(line, p, img->frame->linesize[0]);
> +            init_get_bits(&gb_g, line, img->frame->linesize[0] * 8);
> +            skip_bits(&gb_g, 16);
> +            i = 0;
> +            for (x = 0; x < img->frame->width; x++) {
> +                p    = get_pixel(img->frame, x, y);
> +                p[2] = get_bits(&gb_g, pixel_bits);
> +                i++;
> +                if (i == (1 << width_bits)) {
> +                    skip_bits(&gb_g, 24);
> +                    i = 0;
> +                }
> +            }
> +        }
> +        av_free(line);
> +    }
> +
> +    for (y = 0; y < img->frame->height; y++) {
> +        for (x = 0; x < img->frame->width; x++) {
> +            p = get_pixel(img->frame, x, y);
> +            i = p[2];
> +            pi = get_pixel(pal->frame, i, 0);
> +            if (!pi) {
> +                av_log(s->avctx, AV_LOG_ERROR, "invalid palette index %d\n", 
> i);
> +                return AVERROR_INVALIDDATA;
> +            }
> +            AV_COPY32(p, pi);
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static av_always_inline int color_cache_put(ImageContext *img, uint32_t c)
> +{
> +    int cache_idx =  (0x1E35A7BD * c) >> (32 - img->color_cache_bits);
> +    if (cache_idx >= (1 << img->color_cache_bits))
> +        return AVERROR_BUG;
> +    AV_WB32(&img->color_cache[4 * cache_idx], c);
> +    return 0;
> +}
> +
> +static int decode_entropy_coded_image(WebPContext *s, enum ImageRole role)
> +{
> +    ImageContext *img;
> +    HuffmanGroup *hg;
> +    int i, j, ret, x, y, width;
> +
> +    img = &s->image[role];
> +
> +    if (role == IMAGE_ROLE_ARGB) {
> +        s->subtract_green = 0;
> +        s->nb_transforms  = 0;
> +        ret = 0;
> +        while (get_bits1(&s->gb)) {
> +            enum TransformType transform = get_bits(&s->gb, 2);
> +            s->transforms[s->nb_transforms++] = transform;
> +            switch (transform) {
> +            case PREDICTOR_TRANSFORM:
> +                ret = parse_transform_predictor(s);
> +                if (ret < 0)
> +                    return ret;
> +                break;
> +            case COLOR_TRANSFORM:
> +                ret = parse_transform_color(s);
> +                if (ret < 0)
> +                    return ret;
> +                break;
> +            case SUBTRACT_GREEN:
> +                s->subtract_green = 1;
> +                break;
> +            case COLOR_INDEXING_TRANSFORM:
> +                ret = parse_transform_color_indexing(s);
> +                if (ret < 0)
> +                    return ret;
> +                break;
> +            }
> +        }
> +    }
> +
> +    if (get_bits1(&s->gb)) {
> +        img->color_cache_bits = get_bits(&s->gb, 4);
> +        if (img->color_cache_bits < 1 || img->color_cache_bits > 11) {
> +            av_log(s->avctx, AV_LOG_ERROR, "invalid color cache bits: %d\n",
> +                   img->color_cache_bits);
> +            return AVERROR_INVALIDDATA;
> +        }
> +        img->color_cache = av_mallocz_array(1 << img->color_cache_bits, 4);
> +        if (!img->color_cache)
> +            return AVERROR(ENOMEM);
> +    } else {
> +        img->color_cache_bits = 0;
> +    }
> +
> +    img->num_huffman_groups = 1;
> +    s->use_entropy_image    = 0;
> +    if (role == IMAGE_ROLE_ARGB && get_bits1(&s->gb)) {
> +        ret = decode_entropy_image(s, img);
> +        if (ret < 0)
> +            return ret;
> +    }
> +    img->huffman_groups = av_mallocz_array(img->num_huffman_groups,
> +                                           sizeof(*img->huffman_groups));
> +    if (!img->huffman_groups)
> +        return AVERROR(ENOMEM);
> +
> +    for (i = 0; i < img->num_huffman_groups; i++) {
> +        hg = &img->huffman_groups[i];
> +        for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; j++) {
> +            int alphabet_size = alphabet_sizes[j];
> +            if (!j && img->color_cache_bits > 0)
> +                alphabet_size += 1 << img->color_cache_bits;
> +
> +            if (get_bits1(&s->gb)) {
> +                read_huffman_code_simple(s, &hg->huffman_code[j]);
> +            } else {
> +                ret = read_huffman_code_normal(s, &hg->huffman_code[j],
> +                                               alphabet_size);
> +                if (ret < 0)
> +                    return ret;
> +            }
> +        }
> +    }
> +
> +    width = img->frame->width;
> +    if (role == IMAGE_ROLE_ARGB && s->color_index_width_bits > 0)
> +        width = s->reduced_width;
> +
> +    x = 0; y = 0;
> +    while (y < img->frame->height) {
> +        int v;
> +
> +        hg = get_huffman_group(s, img, x, y);
> +        v = huff_reader_get_symbol(&hg->huffman_code[HUFF_IDX_GREEN], 
> &s->gb);
> +        if (v < NUM_LITERAL_CODES) {
> +            /* literal pixel values */
> +            uint8_t *p = get_pixel(img->frame, x, y);
> +            p[2] = v;
> +            p[1] = huff_reader_get_symbol(&hg->huffman_code[HUFF_IDX_RED],   
> &s->gb);
> +            p[3] = huff_reader_get_symbol(&hg->huffman_code[HUFF_IDX_BLUE],  
> &s->gb);
> +            p[0] = huff_reader_get_symbol(&hg->huffman_code[HUFF_IDX_ALPHA], 
> &s->gb);
> +            if (img->color_cache_bits) {
> +                if ((ret = color_cache_put(img, AV_RB32(p))) < 0)
> +                    return ret;
> +            }
> +            x++;
> +            if (x == width) {
> +                x = 0;
> +                y++;
> +            }
> +        } else if (v < NUM_LITERAL_CODES + NUM_LENGTH_CODES) {
> +            /* LZ77 backwards mapping */
> +            int prefix_code, length, distance, ref_x, ref_y;
> +
> +            /* parse length and distance */
> +            prefix_code = v - NUM_LITERAL_CODES;
> +            if (prefix_code < 4) {
> +                length = prefix_code + 1;
> +            } else {
> +                int extra_bits = (prefix_code - 2) >> 1;
> +                int offset     = (2 + (prefix_code & 1)) << extra_bits;
> +                length = offset + get_bits(&s->gb, extra_bits) + 1;
> +            }
> +            prefix_code = 
> huff_reader_get_symbol(&hg->huffman_code[HUFF_IDX_DIST], &s->gb);
> +            if (prefix_code < 4) {
> +                distance = prefix_code + 1;
> +            } else {
> +                int extra_bits = (prefix_code - 2) >> 1;
> +                int offset     = (2 + (prefix_code & 1)) << extra_bits;
> +                distance = offset + get_bits(&s->gb, extra_bits) + 1;
> +            }
> +
> +            /* find reference location */
> +            if (distance <= NUM_SHORT_DISTANCES) {
> +                int xi = lz77_distance_offsets[distance - 1][0];
> +                int yi = lz77_distance_offsets[distance - 1][1];
> +                distance = FFMAX(1, xi + yi * width);
> +            } else {
> +                distance -= NUM_SHORT_DISTANCES;
> +            }
> +            ref_x = x;
> +            ref_y = y;
> +            if (distance <= x) {
> +                ref_x -= distance;
> +                distance = 0;
> +            } else {
> +                ref_x = 0;
> +                distance -= x;
> +            }
> +            while (distance >= width) {
> +                ref_y--;
> +                distance -= width;
> +            }
> +            if (distance > 0) {
> +                ref_x = width - distance;
> +                ref_y--;
> +            }
> +            ref_x = FFMAX(0, ref_x);
> +            ref_y = FFMAX(0, ref_y);
> +
> +            /* copy pixels */
> +            /* source and dest regions can overlap and wrap lines, so just
> +               copy per-pixel */
> +            for (i = 0; i < length; i++) {
> +                uint8_t *p_ref = get_pixel(img->frame, ref_x, ref_y);
> +                uint8_t *p     = get_pixel(img->frame,     x,     y);
> +
> +                AV_COPY32(p, p_ref);
> +                if (img->color_cache_bits) {
> +                    if ((ret = color_cache_put(img, AV_RB32(p))) < 0)
> +                        return ret;
> +                }
> +                x++;
> +                ref_x++;
> +                if (x == width) {
> +                    x = 0;
> +                    y++;
> +                }
> +                if (ref_x == width) {
> +                    ref_x = 0;
> +                    ref_y++;
> +                }
> +                if (y == img->frame->height || ref_y == img->frame->height)
> +                    break;
> +            }
> +        } else {
> +            /* read from color cache */
> +            uint8_t *p = get_pixel(img->frame, x, y);
> +            int cache_idx = v - (NUM_LITERAL_CODES + NUM_LENGTH_CODES);
> +
> +            if (!img->color_cache_bits) {
> +                av_log(s->avctx, AV_LOG_ERROR, "color cache not found\n");
> +                return AVERROR_INVALIDDATA;
> +            }
> +            if (cache_idx >= (1 << img->color_cache_bits)) {
> +                av_log(s->avctx, AV_LOG_ERROR,
> +                       "color cache index out-of-bounds\n");
> +                return AVERROR_INVALIDDATA;
> +            }
> +            AV_COPY32(p, &img->color_cache[4 * cache_idx]);
> +            x++;
> +            if (x == width) {
> +                x = 0;
> +                y++;
> +            }
> +        }
> +    }
> +
> +    if (role == IMAGE_ROLE_ARGB) {
> +        for (i = s->nb_transforms - 1; i >= 0; i--) {
> +            switch (s->transforms[i]) {
> +            case PREDICTOR_TRANSFORM:
> +                ret = apply_predictor_transform(s);
> +                break;
> +            case COLOR_TRANSFORM:
> +                ret = apply_color_transform(s);
> +                break;
> +            case SUBTRACT_GREEN:
> +                ret = apply_subtract_green_transform(s);
> +                break;
> +            case COLOR_INDEXING_TRANSFORM:
> +                ret = apply_color_indexing_transform(s);
> +                break;
> +            }
> +            if (ret < 0)
> +                return ret;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
>  static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p,
>                                       int *got_frame, uint8_t *data_start,
>                                       unsigned int data_size)
>  {
>      WebPContext *s = avctx->priv_data;
> -    int ret;
> +    ImageContext *img;
> +    int w, h, ret, i;
>  
> +    s->lossless = 1;
>      avctx->pix_fmt = AV_PIX_FMT_ARGB;
>  
> -    /* use dummy dimensions for now */
> -    if (s->width)
> -        avctx->width = s->width;
> -    else
> -        avctx->width = 800;
> -    if (s->height)
> -        avctx->height = s->height;
> -    else
> -        avctx->height  = 600;
> +    ret = init_get_bits(&s->gb, data_start, data_size * 8);
> +    if (ret < 0)
> +        return ret;
> +
> +    if (get_bits(&s->gb, 8) != 0x2F) {
> +        av_log(avctx, AV_LOG_ERROR, "Invalid WebP Lossless signature\n");
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    w = get_bits(&s->gb, 14) + 1;
> +    h = get_bits(&s->gb, 14) + 1;
> +    if (s->width && s->width != w) {
> +        av_log(avctx, AV_LOG_WARNING, "Width mismatch. %d != %d\n",
> +               s->width, w);
> +    }
> +    s->width = w;
> +    if (s->height && s->height != h) {
> +        av_log(avctx, AV_LOG_WARNING, "Height mismatch. %d != %d\n",
> +               s->width, w);
> +    }
> +    s->height = h;
> +    avcodec_set_dimensions(avctx, s->width, s->height);
> +
> +    s->has_alpha = get_bits1(&s->gb);
> +
> +    if (get_bits(&s->gb, 3) != 0x0) {
> +        av_log(avctx, AV_LOG_ERROR, "Invalid WebP Lossless version\n");
> +        return AVERROR_INVALIDDATA;
> +    }
>  
>      if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
>          av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
> @@ -64,6 +1198,23 @@ static int vp8_lossless_decode_frame(AVCodecContext 
> *avctx, AVFrame *p,
>      }
>      memset(p->data[0], 0, p->linesize[0] * avctx->height);
>  
> +    img        = &s->image[IMAGE_ROLE_ARGB];
> +    img->role  = IMAGE_ROLE_ARGB;
> +    img->frame = p;
> +
> +    ret = decode_entropy_coded_image(s, img->role);
> +    if (ret < 0)
> +        return ret;
> +
> +    for (i = 0; i < IMAGE_ROLE_NB; i++)
> +        image_ctx_free(&s->image[i]);
> +    s->predictor_block_size   = 0;
> +    s->color_block_size       = 0;
> +    s->color_index_width_bits = 0;
> +    s->reduced_width          = 0;
> +    s->use_entropy_image      = 0;
> +    s->entropy_size           = 0;
> +
>      *got_frame = 1;
>      p->pict_type = AV_PICTURE_TYPE_I;
>      p->key_frame = 1;
> @@ -85,6 +1236,7 @@ static int vp8_lossy_decode_frame(AVCodecContext *avctx, 
> AVFrame *p,
>          if (s->has_alpha)
>              avctx->pix_fmt = AV_PIX_FMT_YUVA420P;
>      }
> +    s->lossless = 0;
>  
>      if (data_size > INT_MAX) {
>          av_log(avctx, AV_LOG_ERROR, "unsupported chunk size\n");
> @@ -115,6 +1267,7 @@ static int webp_decode_frame(AVCodecContext *avctx, void 
> *data, int *got_frame,
>      unsigned int chunk_type, chunk_size;
>      uint8_t vp8x_flags = 0;
>  
> +    s->avctx  = avctx;
>      s->width  = 0;
>      s->height = 0;
>      *got_frame = 0;
> 

I'll look at the actual code when I'm more awake. Maybe also the
functions could enjoy a webpl instead of image namespace.

lu

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

Reply via email to