xref: /third_party/ffmpeg/libavcodec/mss12.c (revision cabdff1a)
1/*
2 * Copyright (c) 2012 Konstantin Shishkov
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * Common functions for Microsoft Screen 1 and 2
24 */
25
26#include <inttypes.h>
27
28#include "libavutil/intfloat.h"
29#include "libavutil/intreadwrite.h"
30#include "avcodec.h"
31#include "mss12.h"
32
33enum SplitMode {
34    SPLIT_VERT = 0,
35    SPLIT_HOR,
36    SPLIT_NONE
37};
38
39static const int sec_order_sizes[4] = { 1, 7, 6, 1 };
40
41enum ContextDirection {
42    TOP_LEFT = 0,
43    TOP,
44    TOP_RIGHT,
45    LEFT
46};
47
48static int model_calc_threshold(Model *m)
49{
50    int thr;
51
52    thr = 2 * m->weights[m->num_syms] - 1;
53    thr = ((thr >> 1) + 4 * m->cum_prob[0]) / thr;
54
55    return FFMIN(thr, 0x3FFF);
56}
57
58static void model_reset(Model *m)
59{
60    int i;
61
62    for (i = 0; i <= m->num_syms; i++) {
63        m->weights[i]  = 1;
64        m->cum_prob[i] = m->num_syms - i;
65    }
66    m->weights[0] = 0;
67    for (i = 0; i < m->num_syms; i++)
68        m->idx2sym[i + 1] = i;
69}
70
71static av_cold void model_init(Model *m, int num_syms, int thr_weight)
72{
73    m->num_syms   = num_syms;
74    m->thr_weight = thr_weight;
75    m->threshold  = num_syms * thr_weight;
76}
77
78static void model_rescale_weights(Model *m)
79{
80    int i;
81    int cum_prob;
82
83    if (m->thr_weight == THRESH_ADAPTIVE)
84        m->threshold = model_calc_threshold(m);
85    while (m->cum_prob[0] > m->threshold) {
86        cum_prob = 0;
87        for (i = m->num_syms; i >= 0; i--) {
88            m->cum_prob[i] = cum_prob;
89            m->weights[i]  = (m->weights[i] + 1) >> 1;
90            cum_prob      += m->weights[i];
91        }
92    }
93}
94
95void ff_mss12_model_update(Model *m, int val)
96{
97    int i;
98
99    if (m->weights[val] == m->weights[val - 1]) {
100        for (i = val; m->weights[i - 1] == m->weights[val]; i--);
101        if (i != val) {
102            int sym1, sym2;
103
104            sym1 = m->idx2sym[val];
105            sym2 = m->idx2sym[i];
106
107            m->idx2sym[val]  = sym2;
108            m->idx2sym[i]    = sym1;
109
110            val = i;
111        }
112    }
113    m->weights[val]++;
114    for (i = val - 1; i >= 0; i--)
115        m->cum_prob[i]++;
116    model_rescale_weights(m);
117}
118
119static void pixctx_reset(PixContext *ctx)
120{
121    int i, j;
122
123    if (!ctx->special_initial_cache)
124        for (i = 0; i < ctx->cache_size; i++)
125            ctx->cache[i] = i;
126    else {
127        ctx->cache[0] = 1;
128        ctx->cache[1] = 2;
129        ctx->cache[2] = 4;
130    }
131
132    model_reset(&ctx->cache_model);
133    model_reset(&ctx->full_model);
134
135    for (i = 0; i < 15; i++)
136        for (j = 0; j < 4; j++)
137            model_reset(&ctx->sec_models[i][j]);
138}
139
140static av_cold void pixctx_init(PixContext *ctx, int cache_size,
141                                int full_model_syms, int special_initial_cache)
142{
143    int i, j, k, idx;
144
145    ctx->cache_size            = cache_size + 4;
146    ctx->num_syms              = cache_size;
147    ctx->special_initial_cache = special_initial_cache;
148
149    model_init(&ctx->cache_model, ctx->num_syms + 1, THRESH_LOW);
150    model_init(&ctx->full_model, full_model_syms, THRESH_HIGH);
151
152    for (i = 0, idx = 0; i < 4; i++)
153        for (j = 0; j < sec_order_sizes[i]; j++, idx++)
154            for (k = 0; k < 4; k++)
155                model_init(&ctx->sec_models[idx][k], 2 + i,
156                           i ? THRESH_LOW : THRESH_ADAPTIVE);
157}
158
159static av_always_inline int decode_pixel(ArithCoder *acoder, PixContext *pctx,
160                                         uint8_t *ngb, int num_ngb, int any_ngb)
161{
162    int i, val, pix;
163
164    if (acoder->overread > MAX_OVERREAD)
165        return AVERROR_INVALIDDATA;
166    val = acoder->get_model_sym(acoder, &pctx->cache_model);
167    if (val < pctx->num_syms) {
168        if (any_ngb) {
169            int idx, j;
170
171            idx = 0;
172            for (i = 0; i < pctx->cache_size; i++) {
173                for (j = 0; j < num_ngb; j++)
174                    if (pctx->cache[i] == ngb[j])
175                        break;
176                if (j == num_ngb) {
177                    if (idx == val)
178                        break;
179                    idx++;
180                }
181            }
182            val = FFMIN(i, pctx->cache_size - 1);
183        }
184        pix = pctx->cache[val];
185    } else {
186        pix = acoder->get_model_sym(acoder, &pctx->full_model);
187        for (i = 0; i < pctx->cache_size - 1; i++)
188            if (pctx->cache[i] == pix)
189                break;
190        val = i;
191    }
192    if (val) {
193        for (i = val; i > 0; i--)
194            pctx->cache[i] = pctx->cache[i - 1];
195        pctx->cache[0] = pix;
196    }
197
198    return pix;
199}
200
201static int decode_pixel_in_context(ArithCoder *acoder, PixContext *pctx,
202                                   uint8_t *src, ptrdiff_t stride, int x, int y,
203                                   int has_right)
204{
205    uint8_t neighbours[4];
206    uint8_t ref_pix[4];
207    int nlen;
208    int layer = 0, sub;
209    int pix;
210    int i, j;
211
212    if (!y) {
213        memset(neighbours, src[-1], 4);
214    } else {
215        neighbours[TOP] = src[-stride];
216        if (!x) {
217            neighbours[TOP_LEFT] = neighbours[LEFT] = neighbours[TOP];
218        } else {
219            neighbours[TOP_LEFT] = src[-stride - 1];
220            neighbours[    LEFT] = src[-1];
221        }
222        if (has_right)
223            neighbours[TOP_RIGHT] = src[-stride + 1];
224        else
225            neighbours[TOP_RIGHT] = neighbours[TOP];
226    }
227
228    sub = 0;
229    if (x >= 2 && src[-2] == neighbours[LEFT])
230        sub  = 1;
231    if (y >= 2 && src[-2 * stride] == neighbours[TOP])
232        sub |= 2;
233
234    nlen = 1;
235    ref_pix[0] = neighbours[0];
236    for (i = 1; i < 4; i++) {
237        for (j = 0; j < nlen; j++)
238            if (ref_pix[j] == neighbours[i])
239                break;
240        if (j == nlen)
241            ref_pix[nlen++] = neighbours[i];
242    }
243
244    switch (nlen) {
245    case 1:
246        layer = 0;
247        break;
248    case 2:
249        if (neighbours[TOP] == neighbours[TOP_LEFT]) {
250            if (neighbours[TOP_RIGHT] == neighbours[TOP_LEFT])
251                layer = 1;
252            else if (neighbours[LEFT] == neighbours[TOP_LEFT])
253                layer = 2;
254            else
255                layer = 3;
256        } else if (neighbours[TOP_RIGHT] == neighbours[TOP_LEFT]) {
257            if (neighbours[LEFT] == neighbours[TOP_LEFT])
258                layer = 4;
259            else
260                layer = 5;
261        } else if (neighbours[LEFT] == neighbours[TOP_LEFT]) {
262            layer = 6;
263        } else {
264            layer = 7;
265        }
266        break;
267    case 3:
268        if (neighbours[TOP] == neighbours[TOP_LEFT])
269            layer = 8;
270        else if (neighbours[TOP_RIGHT] == neighbours[TOP_LEFT])
271            layer = 9;
272        else if (neighbours[LEFT] == neighbours[TOP_LEFT])
273            layer = 10;
274        else if (neighbours[TOP_RIGHT] == neighbours[TOP])
275            layer = 11;
276        else if (neighbours[TOP] == neighbours[LEFT])
277            layer = 12;
278        else
279            layer = 13;
280        break;
281    case 4:
282        layer = 14;
283        break;
284    }
285
286    pix = acoder->get_model_sym(acoder,
287                                &pctx->sec_models[layer][sub]);
288    if (pix < nlen)
289        return ref_pix[pix];
290    else
291        return decode_pixel(acoder, pctx, ref_pix, nlen, 1);
292}
293
294static int decode_region(ArithCoder *acoder, uint8_t *dst, uint8_t *rgb_dst,
295                         int x, int y, int width, int height, ptrdiff_t stride,
296                         ptrdiff_t rgb_stride, PixContext *pctx,
297                         const uint32_t *pal)
298{
299    int i, j, p;
300
301    rgb_stride = rgb_dst ? rgb_stride : 0;
302    rgb_dst    = rgb_dst ? rgb_dst + x * 3 + y * rgb_stride : NULL;
303    dst += x + y * stride;
304
305    for (j = 0; j < height; j++) {
306        for (i = 0; i < width; i++) {
307            if (!i && !j)
308                p = decode_pixel(acoder, pctx, NULL, 0, 0);
309            else
310                p = decode_pixel_in_context(acoder, pctx, dst + i, stride,
311                                            i, j, width - i - 1);
312            if (p < 0)
313                return p;
314            dst[i] = p;
315
316            if (rgb_dst)
317                AV_WB24(rgb_dst + i * 3, pal[p]);
318        }
319        dst     += stride;
320        rgb_dst  = FF_PTR_ADD(rgb_dst, rgb_stride);
321    }
322
323    return 0;
324}
325
326static void copy_rectangles(MSS12Context const *c,
327                            int x, int y, int width, int height)
328{
329    int j;
330
331    if (c->last_rgb_pic)
332        for (j = y; j < y + height; j++) {
333            memcpy(c->rgb_pic      + j * c->rgb_stride + x * 3,
334                   c->last_rgb_pic + j * c->rgb_stride + x * 3,
335                   width * 3);
336            memcpy(c->pal_pic      + j * c->pal_stride + x,
337                   c->last_pal_pic + j * c->pal_stride + x,
338                   width);
339        }
340}
341
342static int motion_compensation(MSS12Context const *c,
343                               int x, int y, int width, int height)
344{
345    if (x + c->mvX < 0 || x + c->mvX + width  > c->avctx->width  ||
346        y + c->mvY < 0 || y + c->mvY + height > c->avctx->height ||
347        !c->rgb_pic)
348        return -1;
349    else {
350        uint8_t *dst     = c->pal_pic + x     + y * c->pal_stride;
351        uint8_t *rgb_dst = c->rgb_pic + x * 3 + y * c->rgb_stride;
352        uint8_t *src;
353        uint8_t *rgb_src;
354        int j;
355        x += c->mvX;
356        y += c->mvY;
357        if (c->last_rgb_pic) {
358            src     = c->last_pal_pic + x +     y * c->pal_stride;
359            rgb_src = c->last_rgb_pic + x * 3 + y * c->rgb_stride;
360        } else {
361            src     = c->pal_pic + x     + y * c->pal_stride;
362            rgb_src = c->rgb_pic + x * 3 + y * c->rgb_stride;
363        }
364        for (j = 0; j < height; j++) {
365            memmove(dst, src, width);
366            memmove(rgb_dst, rgb_src, width * 3);
367            dst     += c->pal_stride;
368            src     += c->pal_stride;
369            rgb_dst += c->rgb_stride;
370            rgb_src += c->rgb_stride;
371        }
372    }
373    return 0;
374}
375
376static int decode_region_masked(MSS12Context const *c, ArithCoder *acoder,
377                                uint8_t *dst, ptrdiff_t stride, uint8_t *mask,
378                                ptrdiff_t mask_stride, int x, int y,
379                                int width, int height,
380                                PixContext *pctx)
381{
382    int i, j, p;
383    uint8_t *rgb_dst = c->rgb_pic + x * 3 + y * c->rgb_stride;
384
385    dst  += x + y * stride;
386    mask += x + y * mask_stride;
387
388    for (j = 0; j < height; j++) {
389        for (i = 0; i < width; i++) {
390            if (c->avctx->err_recognition & AV_EF_EXPLODE &&
391                ( c->rgb_pic && mask[i] != 0x01 && mask[i] != 0x02 && mask[i] != 0x04 ||
392                 !c->rgb_pic && mask[i] != 0x80 && mask[i] != 0xFF))
393                return -1;
394
395            if (mask[i] == 0x02) {
396                copy_rectangles(c, x + i, y + j, 1, 1);
397            } else if (mask[i] == 0x04) {
398                if (motion_compensation(c, x + i, y + j, 1, 1))
399                    return -1;
400            } else if (mask[i] != 0x80) {
401                if (!i && !j)
402                    p = decode_pixel(acoder, pctx, NULL, 0, 0);
403                else
404                    p = decode_pixel_in_context(acoder, pctx, dst + i, stride,
405                                                i, j, width - i - 1);
406                if (p < 0)
407                    return p;
408                dst[i] = p;
409                if (c->rgb_pic)
410                    AV_WB24(rgb_dst + i * 3, c->pal[p]);
411            }
412        }
413        dst     += stride;
414        mask    += mask_stride;
415        rgb_dst += c->rgb_stride;
416    }
417
418    return 0;
419}
420
421static av_cold void slicecontext_init(SliceContext *sc,
422                                      int version, int full_model_syms)
423{
424    model_init(&sc->intra_region, 2, THRESH_ADAPTIVE);
425    model_init(&sc->inter_region, 2, THRESH_ADAPTIVE);
426    model_init(&sc->split_mode,   3, THRESH_HIGH);
427    model_init(&sc->edge_mode,    2, THRESH_HIGH);
428    model_init(&sc->pivot,        3, THRESH_LOW);
429
430    pixctx_init(&sc->intra_pix_ctx, 8, full_model_syms, 0);
431
432    pixctx_init(&sc->inter_pix_ctx, version ? 3 : 2,
433                full_model_syms, version ? 1 : 0);
434}
435
436void ff_mss12_slicecontext_reset(SliceContext *sc)
437{
438    model_reset(&sc->intra_region);
439    model_reset(&sc->inter_region);
440    model_reset(&sc->split_mode);
441    model_reset(&sc->edge_mode);
442    model_reset(&sc->pivot);
443    pixctx_reset(&sc->intra_pix_ctx);
444    pixctx_reset(&sc->inter_pix_ctx);
445}
446
447static int decode_pivot(SliceContext *sc, ArithCoder *acoder, int base)
448{
449    int val, inv;
450
451    inv = acoder->get_model_sym(acoder, &sc->edge_mode);
452    val = acoder->get_model_sym(acoder, &sc->pivot) + 1;
453
454    if (val > 2) {
455        if ((base + 1) / 2 - 2 <= 0)
456            return -1;
457
458        val = acoder->get_number(acoder, (base + 1) / 2 - 2) + 3;
459    }
460
461    if ((unsigned)val >= base)
462        return -1;
463
464    return inv ? base - val : val;
465}
466
467static int decode_region_intra(SliceContext *sc, ArithCoder *acoder,
468                               int x, int y, int width, int height)
469{
470    MSS12Context const *c = sc->c;
471    int mode;
472
473    mode = acoder->get_model_sym(acoder, &sc->intra_region);
474
475    if (!mode) {
476        int i, j, pix, rgb_pix;
477        ptrdiff_t stride     = c->pal_stride;
478        ptrdiff_t rgb_stride = c->rgb_stride;
479        uint8_t *dst     = c->pal_pic + x     + y * stride;
480        uint8_t *rgb_dst = c->rgb_pic ? c->rgb_pic + x * 3 + y * rgb_stride : NULL;
481
482        pix     = decode_pixel(acoder, &sc->intra_pix_ctx, NULL, 0, 0);
483        if (pix < 0)
484            return pix;
485        rgb_pix = c->pal[pix];
486        for (i = 0; i < height; i++, dst += stride) {
487            memset(dst, pix, width);
488            if (rgb_dst) {
489                for (j = 0; j < width * 3; j += 3)
490                    AV_WB24(rgb_dst + j, rgb_pix);
491                rgb_dst += rgb_stride;
492            }
493        }
494    } else {
495        return decode_region(acoder, c->pal_pic, c->rgb_pic,
496                             x, y, width, height, c->pal_stride, c->rgb_stride,
497                             &sc->intra_pix_ctx, &c->pal[0]);
498    }
499
500    return 0;
501}
502
503static int decode_region_inter(SliceContext *sc, ArithCoder *acoder,
504                               int x, int y, int width, int height)
505{
506    MSS12Context const *c = sc->c;
507    int mode;
508
509    mode = acoder->get_model_sym(acoder, &sc->inter_region);
510
511    if (!mode) {
512        mode = decode_pixel(acoder, &sc->inter_pix_ctx, NULL, 0, 0);
513        if (mode < 0)
514            return mode;
515
516        if (c->avctx->err_recognition & AV_EF_EXPLODE &&
517            ( c->rgb_pic && mode != 0x01 && mode != 0x02 && mode != 0x04 ||
518             !c->rgb_pic && mode != 0x80 && mode != 0xFF))
519            return -1;
520
521        if (mode == 0x02)
522            copy_rectangles(c, x, y, width, height);
523        else if (mode == 0x04)
524            return motion_compensation(c, x, y, width, height);
525        else if (mode != 0x80)
526            return decode_region_intra(sc, acoder, x, y, width, height);
527    } else {
528        if (decode_region(acoder, c->mask, NULL,
529                          x, y, width, height, c->mask_stride, 0,
530                          &sc->inter_pix_ctx, &c->pal[0]) < 0)
531            return -1;
532        return decode_region_masked(c, acoder, c->pal_pic,
533                                    c->pal_stride, c->mask,
534                                    c->mask_stride,
535                                    x, y, width, height,
536                                    &sc->intra_pix_ctx);
537    }
538
539    return 0;
540}
541
542int ff_mss12_decode_rect(SliceContext *sc, ArithCoder *acoder,
543                         int x, int y, int width, int height)
544{
545    int mode, pivot;
546    if (acoder->overread > MAX_OVERREAD)
547        return AVERROR_INVALIDDATA;
548
549    mode = acoder->get_model_sym(acoder, &sc->split_mode);
550
551    switch (mode) {
552    case SPLIT_VERT:
553        if ((pivot = decode_pivot(sc, acoder, height)) < 1)
554            return -1;
555        if (ff_mss12_decode_rect(sc, acoder, x, y, width, pivot))
556            return -1;
557        if (ff_mss12_decode_rect(sc, acoder, x, y + pivot, width, height - pivot))
558            return -1;
559        break;
560    case SPLIT_HOR:
561        if ((pivot = decode_pivot(sc, acoder, width)) < 1)
562            return -1;
563        if (ff_mss12_decode_rect(sc, acoder, x, y, pivot, height))
564            return -1;
565        if (ff_mss12_decode_rect(sc, acoder, x + pivot, y, width - pivot, height))
566            return -1;
567        break;
568    case SPLIT_NONE:
569        if (sc->c->keyframe)
570            return decode_region_intra(sc, acoder, x, y, width, height);
571        else
572            return decode_region_inter(sc, acoder, x, y, width, height);
573    default:
574        return -1;
575    }
576
577    return 0;
578}
579
580av_cold int ff_mss12_decode_init(MSS12Context *c, int version,
581                                 SliceContext* sc1, SliceContext *sc2)
582{
583    AVCodecContext *avctx = c->avctx;
584    int i;
585
586    if (avctx->extradata_size < 52 + 256 * 3) {
587        av_log(avctx, AV_LOG_ERROR, "Insufficient extradata size %d\n",
588               avctx->extradata_size);
589        return AVERROR_INVALIDDATA;
590    }
591
592    if (AV_RB32(avctx->extradata) < avctx->extradata_size) {
593        av_log(avctx, AV_LOG_ERROR,
594               "Insufficient extradata size: expected %"PRIu32" got %d\n",
595               AV_RB32(avctx->extradata),
596               avctx->extradata_size);
597        return AVERROR_INVALIDDATA;
598    }
599
600    avctx->coded_width  = FFMAX(AV_RB32(avctx->extradata + 20), avctx->width);
601    avctx->coded_height = FFMAX(AV_RB32(avctx->extradata + 24), avctx->height);
602    if (avctx->coded_width > 4096 || avctx->coded_height > 4096) {
603        av_log(avctx, AV_LOG_ERROR, "Frame dimensions %dx%d too large",
604               avctx->coded_width, avctx->coded_height);
605        return AVERROR_INVALIDDATA;
606    }
607    if (avctx->coded_width < 1 || avctx->coded_height < 1) {
608        av_log(avctx, AV_LOG_ERROR, "Frame dimensions %dx%d too small",
609               avctx->coded_width, avctx->coded_height);
610        return AVERROR_INVALIDDATA;
611    }
612
613    av_log(avctx, AV_LOG_DEBUG, "Encoder version %"PRIu32".%"PRIu32"\n",
614           AV_RB32(avctx->extradata + 4), AV_RB32(avctx->extradata + 8));
615    if (version != AV_RB32(avctx->extradata + 4) > 1) {
616        av_log(avctx, AV_LOG_ERROR,
617               "Header version doesn't match codec tag\n");
618        return -1;
619    }
620
621    c->free_colours = AV_RB32(avctx->extradata + 48);
622    if ((unsigned)c->free_colours > 256) {
623        av_log(avctx, AV_LOG_ERROR,
624               "Incorrect number of changeable palette entries: %d\n",
625               c->free_colours);
626        return AVERROR_INVALIDDATA;
627    }
628    av_log(avctx, AV_LOG_DEBUG, "%d free colour(s)\n", c->free_colours);
629
630    av_log(avctx, AV_LOG_DEBUG, "Display dimensions %"PRIu32"x%"PRIu32"\n",
631           AV_RB32(avctx->extradata + 12), AV_RB32(avctx->extradata + 16));
632    av_log(avctx, AV_LOG_DEBUG, "Coded dimensions %dx%d\n",
633           avctx->coded_width, avctx->coded_height);
634    av_log(avctx, AV_LOG_DEBUG, "%g frames per second\n",
635           av_int2float(AV_RB32(avctx->extradata + 28)));
636    av_log(avctx, AV_LOG_DEBUG, "Bitrate %"PRIu32" bps\n",
637           AV_RB32(avctx->extradata + 32));
638    av_log(avctx, AV_LOG_DEBUG, "Max. lead time %g ms\n",
639           av_int2float(AV_RB32(avctx->extradata + 36)));
640    av_log(avctx, AV_LOG_DEBUG, "Max. lag time %g ms\n",
641           av_int2float(AV_RB32(avctx->extradata + 40)));
642    av_log(avctx, AV_LOG_DEBUG, "Max. seek time %g ms\n",
643           av_int2float(AV_RB32(avctx->extradata + 44)));
644
645    if (version) {
646        if (avctx->extradata_size < 60 + 256 * 3) {
647            av_log(avctx, AV_LOG_ERROR,
648                   "Insufficient extradata size %d for v2\n",
649                   avctx->extradata_size);
650            return AVERROR_INVALIDDATA;
651        }
652
653        c->slice_split = AV_RB32(avctx->extradata + 52);
654        av_log(avctx, AV_LOG_DEBUG, "Slice split %d\n", c->slice_split);
655
656        c->full_model_syms = AV_RB32(avctx->extradata + 56);
657        if (c->full_model_syms < 2 || c->full_model_syms > 256) {
658            av_log(avctx, AV_LOG_ERROR,
659                   "Incorrect number of used colours %d\n",
660                   c->full_model_syms);
661            return AVERROR_INVALIDDATA;
662        }
663        av_log(avctx, AV_LOG_DEBUG, "Used colours %d\n",
664               c->full_model_syms);
665    } else {
666        c->slice_split     = 0;
667        c->full_model_syms = 256;
668    }
669
670    for (i = 0; i < 256; i++)
671        c->pal[i] = 0xFFU << 24 | AV_RB24(avctx->extradata + 52 +
672                            (version ? 8 : 0) + i * 3);
673
674    c->mask_stride = FFALIGN(avctx->width, 16);
675    c->mask        = av_malloc_array(c->mask_stride, avctx->height);
676    if (!c->mask) {
677        av_log(avctx, AV_LOG_ERROR, "Cannot allocate mask plane\n");
678        return AVERROR(ENOMEM);
679    }
680
681    sc1->c = c;
682    slicecontext_init(sc1, version, c->full_model_syms);
683    if (c->slice_split) {
684        sc2->c = c;
685        slicecontext_init(sc2, version, c->full_model_syms);
686    }
687    c->corrupted = 1;
688
689    return 0;
690}
691
692av_cold int ff_mss12_decode_end(MSS12Context *c)
693{
694    av_freep(&c->mask);
695
696    return 0;
697}
698