1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Lagarith lossless decoder
3cabdff1aSopenharmony_ci * Copyright (c) 2009 Nathan Caldwell <saintdev (at) gmail.com>
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci/**
23cabdff1aSopenharmony_ci * @file
24cabdff1aSopenharmony_ci * Lagarith lossless decoder
25cabdff1aSopenharmony_ci * @author Nathan Caldwell
26cabdff1aSopenharmony_ci */
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_ci#include <inttypes.h>
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_ci#include "avcodec.h"
31cabdff1aSopenharmony_ci#include "codec_internal.h"
32cabdff1aSopenharmony_ci#include "get_bits.h"
33cabdff1aSopenharmony_ci#include "mathops.h"
34cabdff1aSopenharmony_ci#include "lagarithrac.h"
35cabdff1aSopenharmony_ci#include "lossless_videodsp.h"
36cabdff1aSopenharmony_ci#include "thread.h"
37cabdff1aSopenharmony_ci
38cabdff1aSopenharmony_cienum LagarithFrameType {
39cabdff1aSopenharmony_ci    FRAME_RAW           = 1,    /**< uncompressed */
40cabdff1aSopenharmony_ci    FRAME_U_RGB24       = 2,    /**< unaligned RGB24 */
41cabdff1aSopenharmony_ci    FRAME_ARITH_YUY2    = 3,    /**< arithmetic coded YUY2 */
42cabdff1aSopenharmony_ci    FRAME_ARITH_RGB24   = 4,    /**< arithmetic coded RGB24 */
43cabdff1aSopenharmony_ci    FRAME_SOLID_GRAY    = 5,    /**< solid grayscale color frame */
44cabdff1aSopenharmony_ci    FRAME_SOLID_COLOR   = 6,    /**< solid non-grayscale color frame */
45cabdff1aSopenharmony_ci    FRAME_OLD_ARITH_RGB = 7,    /**< obsolete arithmetic coded RGB (no longer encoded by upstream since version 1.1.0) */
46cabdff1aSopenharmony_ci    FRAME_ARITH_RGBA    = 8,    /**< arithmetic coded RGBA */
47cabdff1aSopenharmony_ci    FRAME_SOLID_RGBA    = 9,    /**< solid RGBA color frame */
48cabdff1aSopenharmony_ci    FRAME_ARITH_YV12    = 10,   /**< arithmetic coded YV12 */
49cabdff1aSopenharmony_ci    FRAME_REDUCED_RES   = 11,   /**< reduced resolution YV12 frame */
50cabdff1aSopenharmony_ci};
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_citypedef struct LagarithContext {
53cabdff1aSopenharmony_ci    AVCodecContext *avctx;
54cabdff1aSopenharmony_ci    LLVidDSPContext llviddsp;
55cabdff1aSopenharmony_ci    int zeros;                  /**< number of consecutive zero bytes encountered */
56cabdff1aSopenharmony_ci    int zeros_rem;              /**< number of zero bytes remaining to output */
57cabdff1aSopenharmony_ci} LagarithContext;
58cabdff1aSopenharmony_ci
59cabdff1aSopenharmony_ci/**
60cabdff1aSopenharmony_ci * Compute the 52-bit mantissa of 1/(double)denom.
61cabdff1aSopenharmony_ci * This crazy format uses floats in an entropy coder and we have to match x86
62cabdff1aSopenharmony_ci * rounding exactly, thus ordinary floats aren't portable enough.
63cabdff1aSopenharmony_ci * @param denom denominator
64cabdff1aSopenharmony_ci * @return 52-bit mantissa
65cabdff1aSopenharmony_ci * @see softfloat_mul
66cabdff1aSopenharmony_ci */
67cabdff1aSopenharmony_cistatic uint64_t softfloat_reciprocal(uint32_t denom)
68cabdff1aSopenharmony_ci{
69cabdff1aSopenharmony_ci    int shift = av_log2(denom - 1) + 1;
70cabdff1aSopenharmony_ci    uint64_t ret = (1ULL << 52) / denom;
71cabdff1aSopenharmony_ci    uint64_t err = (1ULL << 52) - ret * denom;
72cabdff1aSopenharmony_ci    ret <<= shift;
73cabdff1aSopenharmony_ci    err <<= shift;
74cabdff1aSopenharmony_ci    err +=  denom / 2;
75cabdff1aSopenharmony_ci    return ret + err / denom;
76cabdff1aSopenharmony_ci}
77cabdff1aSopenharmony_ci
78cabdff1aSopenharmony_ci/**
79cabdff1aSopenharmony_ci * (uint32_t)(x*f), where f has the given mantissa, and exponent 0
80cabdff1aSopenharmony_ci * Used in combination with softfloat_reciprocal computes x/(double)denom.
81cabdff1aSopenharmony_ci * @param x 32-bit integer factor
82cabdff1aSopenharmony_ci * @param mantissa mantissa of f with exponent 0
83cabdff1aSopenharmony_ci * @return 32-bit integer value (x*f)
84cabdff1aSopenharmony_ci * @see softfloat_reciprocal
85cabdff1aSopenharmony_ci */
86cabdff1aSopenharmony_cistatic uint32_t softfloat_mul(uint32_t x, uint64_t mantissa)
87cabdff1aSopenharmony_ci{
88cabdff1aSopenharmony_ci    uint64_t l = x * (mantissa & 0xffffffff);
89cabdff1aSopenharmony_ci    uint64_t h = x * (mantissa >> 32);
90cabdff1aSopenharmony_ci    h += l >> 32;
91cabdff1aSopenharmony_ci    l &= 0xffffffff;
92cabdff1aSopenharmony_ci    l += 1LL << av_log2(h >> 21);
93cabdff1aSopenharmony_ci    h += l >> 32;
94cabdff1aSopenharmony_ci    return h >> 20;
95cabdff1aSopenharmony_ci}
96cabdff1aSopenharmony_ci
97cabdff1aSopenharmony_cistatic uint8_t lag_calc_zero_run(int8_t x)
98cabdff1aSopenharmony_ci{
99cabdff1aSopenharmony_ci    return (x * 2) ^ (x >> 7);
100cabdff1aSopenharmony_ci}
101cabdff1aSopenharmony_ci
102cabdff1aSopenharmony_cistatic int lag_decode_prob(GetBitContext *gb, uint32_t *value)
103cabdff1aSopenharmony_ci{
104cabdff1aSopenharmony_ci    static const uint8_t series[] = { 1, 2, 3, 5, 8, 13, 21 };
105cabdff1aSopenharmony_ci    int i;
106cabdff1aSopenharmony_ci    int bit     = 0;
107cabdff1aSopenharmony_ci    int bits    = 0;
108cabdff1aSopenharmony_ci    int prevbit = 0;
109cabdff1aSopenharmony_ci    unsigned val;
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_ci    for (i = 0; i < 7; i++) {
112cabdff1aSopenharmony_ci        if (prevbit && bit)
113cabdff1aSopenharmony_ci            break;
114cabdff1aSopenharmony_ci        prevbit = bit;
115cabdff1aSopenharmony_ci        bit = get_bits1(gb);
116cabdff1aSopenharmony_ci        if (bit && !prevbit)
117cabdff1aSopenharmony_ci            bits += series[i];
118cabdff1aSopenharmony_ci    }
119cabdff1aSopenharmony_ci    bits--;
120cabdff1aSopenharmony_ci    if (bits < 0 || bits > 31) {
121cabdff1aSopenharmony_ci        *value = 0;
122cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
123cabdff1aSopenharmony_ci    } else if (bits == 0) {
124cabdff1aSopenharmony_ci        *value = 0;
125cabdff1aSopenharmony_ci        return 0;
126cabdff1aSopenharmony_ci    }
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci    val  = get_bits_long(gb, bits);
129cabdff1aSopenharmony_ci    val |= 1U << bits;
130cabdff1aSopenharmony_ci
131cabdff1aSopenharmony_ci    *value = val - 1;
132cabdff1aSopenharmony_ci
133cabdff1aSopenharmony_ci    return 0;
134cabdff1aSopenharmony_ci}
135cabdff1aSopenharmony_ci
136cabdff1aSopenharmony_cistatic int lag_read_prob_header(lag_rac *rac, GetBitContext *gb)
137cabdff1aSopenharmony_ci{
138cabdff1aSopenharmony_ci    int i, j, scale_factor;
139cabdff1aSopenharmony_ci    unsigned prob, cumulative_target;
140cabdff1aSopenharmony_ci    unsigned cumul_prob = 0;
141cabdff1aSopenharmony_ci    unsigned scaled_cumul_prob = 0;
142cabdff1aSopenharmony_ci    int nnz = 0;
143cabdff1aSopenharmony_ci
144cabdff1aSopenharmony_ci    rac->prob[0] = 0;
145cabdff1aSopenharmony_ci    rac->prob[257] = UINT_MAX;
146cabdff1aSopenharmony_ci    /* Read probabilities from bitstream */
147cabdff1aSopenharmony_ci    for (i = 1; i < 257; i++) {
148cabdff1aSopenharmony_ci        if (lag_decode_prob(gb, &rac->prob[i]) < 0) {
149cabdff1aSopenharmony_ci            av_log(rac->avctx, AV_LOG_ERROR, "Invalid probability encountered.\n");
150cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
151cabdff1aSopenharmony_ci        }
152cabdff1aSopenharmony_ci        if ((uint64_t)cumul_prob + rac->prob[i] > UINT_MAX) {
153cabdff1aSopenharmony_ci            av_log(rac->avctx, AV_LOG_ERROR, "Integer overflow encountered in cumulative probability calculation.\n");
154cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
155cabdff1aSopenharmony_ci        }
156cabdff1aSopenharmony_ci        cumul_prob += rac->prob[i];
157cabdff1aSopenharmony_ci        if (!rac->prob[i]) {
158cabdff1aSopenharmony_ci            if (lag_decode_prob(gb, &prob)) {
159cabdff1aSopenharmony_ci                av_log(rac->avctx, AV_LOG_ERROR, "Invalid probability run encountered.\n");
160cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
161cabdff1aSopenharmony_ci            }
162cabdff1aSopenharmony_ci            if (prob > 256 - i)
163cabdff1aSopenharmony_ci                prob = 256 - i;
164cabdff1aSopenharmony_ci            for (j = 0; j < prob; j++)
165cabdff1aSopenharmony_ci                rac->prob[++i] = 0;
166cabdff1aSopenharmony_ci        }else {
167cabdff1aSopenharmony_ci            nnz++;
168cabdff1aSopenharmony_ci        }
169cabdff1aSopenharmony_ci    }
170cabdff1aSopenharmony_ci
171cabdff1aSopenharmony_ci    if (!cumul_prob) {
172cabdff1aSopenharmony_ci        av_log(rac->avctx, AV_LOG_ERROR, "All probabilities are 0!\n");
173cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
174cabdff1aSopenharmony_ci    }
175cabdff1aSopenharmony_ci
176cabdff1aSopenharmony_ci    if (nnz == 1 && (show_bits_long(gb, 32) & 0xFFFFFF)) {
177cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
178cabdff1aSopenharmony_ci    }
179cabdff1aSopenharmony_ci
180cabdff1aSopenharmony_ci    /* Scale probabilities so cumulative probability is an even power of 2. */
181cabdff1aSopenharmony_ci    scale_factor = av_log2(cumul_prob);
182cabdff1aSopenharmony_ci
183cabdff1aSopenharmony_ci    if (cumul_prob & (cumul_prob - 1)) {
184cabdff1aSopenharmony_ci        uint64_t mul = softfloat_reciprocal(cumul_prob);
185cabdff1aSopenharmony_ci        for (i = 1; i <= 128; i++) {
186cabdff1aSopenharmony_ci            rac->prob[i] = softfloat_mul(rac->prob[i], mul);
187cabdff1aSopenharmony_ci            scaled_cumul_prob += rac->prob[i];
188cabdff1aSopenharmony_ci        }
189cabdff1aSopenharmony_ci        if (scaled_cumul_prob <= 0) {
190cabdff1aSopenharmony_ci            av_log(rac->avctx, AV_LOG_ERROR, "Scaled probabilities invalid\n");
191cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
192cabdff1aSopenharmony_ci        }
193cabdff1aSopenharmony_ci        for (; i < 257; i++) {
194cabdff1aSopenharmony_ci            rac->prob[i] = softfloat_mul(rac->prob[i], mul);
195cabdff1aSopenharmony_ci            scaled_cumul_prob += rac->prob[i];
196cabdff1aSopenharmony_ci        }
197cabdff1aSopenharmony_ci
198cabdff1aSopenharmony_ci        scale_factor++;
199cabdff1aSopenharmony_ci        if (scale_factor >= 32U)
200cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
201cabdff1aSopenharmony_ci        cumulative_target = 1U << scale_factor;
202cabdff1aSopenharmony_ci
203cabdff1aSopenharmony_ci        if (scaled_cumul_prob > cumulative_target) {
204cabdff1aSopenharmony_ci            av_log(rac->avctx, AV_LOG_ERROR,
205cabdff1aSopenharmony_ci                   "Scaled probabilities are larger than target!\n");
206cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
207cabdff1aSopenharmony_ci        }
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci        scaled_cumul_prob = cumulative_target - scaled_cumul_prob;
210cabdff1aSopenharmony_ci
211cabdff1aSopenharmony_ci        for (i = 1; scaled_cumul_prob; i = (i & 0x7f) + 1) {
212cabdff1aSopenharmony_ci            if (rac->prob[i]) {
213cabdff1aSopenharmony_ci                rac->prob[i]++;
214cabdff1aSopenharmony_ci                scaled_cumul_prob--;
215cabdff1aSopenharmony_ci            }
216cabdff1aSopenharmony_ci            /* Comment from reference source:
217cabdff1aSopenharmony_ci             * if (b & 0x80 == 0) {     // order of operations is 'wrong'; it has been left this way
218cabdff1aSopenharmony_ci             *                          // since the compression change is negligible and fixing it
219cabdff1aSopenharmony_ci             *                          // breaks backwards compatibility
220cabdff1aSopenharmony_ci             *      b =- (signed int)b;
221cabdff1aSopenharmony_ci             *      b &= 0xFF;
222cabdff1aSopenharmony_ci             * } else {
223cabdff1aSopenharmony_ci             *      b++;
224cabdff1aSopenharmony_ci             *      b &= 0x7f;
225cabdff1aSopenharmony_ci             * }
226cabdff1aSopenharmony_ci             */
227cabdff1aSopenharmony_ci        }
228cabdff1aSopenharmony_ci    }
229cabdff1aSopenharmony_ci
230cabdff1aSopenharmony_ci    if (scale_factor > 23)
231cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
232cabdff1aSopenharmony_ci
233cabdff1aSopenharmony_ci    rac->scale = scale_factor;
234cabdff1aSopenharmony_ci
235cabdff1aSopenharmony_ci    /* Fill probability array with cumulative probability for each symbol. */
236cabdff1aSopenharmony_ci    for (i = 1; i < 257; i++)
237cabdff1aSopenharmony_ci        rac->prob[i] += rac->prob[i - 1];
238cabdff1aSopenharmony_ci
239cabdff1aSopenharmony_ci    return 0;
240cabdff1aSopenharmony_ci}
241cabdff1aSopenharmony_ci
242cabdff1aSopenharmony_cistatic void add_lag_median_prediction(uint8_t *dst, uint8_t *src1,
243cabdff1aSopenharmony_ci                                      uint8_t *diff, int w, int *left,
244cabdff1aSopenharmony_ci                                      int *left_top)
245cabdff1aSopenharmony_ci{
246cabdff1aSopenharmony_ci    /* This is almost identical to add_hfyu_median_pred in huffyuvdsp.h.
247cabdff1aSopenharmony_ci     * However the &0xFF on the gradient predictor yields incorrect output
248cabdff1aSopenharmony_ci     * for lagarith.
249cabdff1aSopenharmony_ci     */
250cabdff1aSopenharmony_ci    int i;
251cabdff1aSopenharmony_ci    uint8_t l, lt;
252cabdff1aSopenharmony_ci
253cabdff1aSopenharmony_ci    l  = *left;
254cabdff1aSopenharmony_ci    lt = *left_top;
255cabdff1aSopenharmony_ci
256cabdff1aSopenharmony_ci    for (i = 0; i < w; i++) {
257cabdff1aSopenharmony_ci        l = mid_pred(l, src1[i], l + src1[i] - lt) + diff[i];
258cabdff1aSopenharmony_ci        lt = src1[i];
259cabdff1aSopenharmony_ci        dst[i] = l;
260cabdff1aSopenharmony_ci    }
261cabdff1aSopenharmony_ci
262cabdff1aSopenharmony_ci    *left     = l;
263cabdff1aSopenharmony_ci    *left_top = lt;
264cabdff1aSopenharmony_ci}
265cabdff1aSopenharmony_ci
266cabdff1aSopenharmony_cistatic void lag_pred_line(LagarithContext *l, uint8_t *buf,
267cabdff1aSopenharmony_ci                          int width, int stride, int line)
268cabdff1aSopenharmony_ci{
269cabdff1aSopenharmony_ci    int L, TL;
270cabdff1aSopenharmony_ci
271cabdff1aSopenharmony_ci    if (!line) {
272cabdff1aSopenharmony_ci        /* Left prediction only for first line */
273cabdff1aSopenharmony_ci        L = l->llviddsp.add_left_pred(buf, buf, width, 0);
274cabdff1aSopenharmony_ci    } else {
275cabdff1aSopenharmony_ci        /* Left pixel is actually prev_row[width] */
276cabdff1aSopenharmony_ci        L = buf[width - stride - 1];
277cabdff1aSopenharmony_ci
278cabdff1aSopenharmony_ci        if (line == 1) {
279cabdff1aSopenharmony_ci            /* Second line, left predict first pixel, the rest of the line is median predicted
280cabdff1aSopenharmony_ci             * NOTE: In the case of RGB this pixel is top predicted */
281cabdff1aSopenharmony_ci            TL = l->avctx->pix_fmt == AV_PIX_FMT_YUV420P ? buf[-stride] : L;
282cabdff1aSopenharmony_ci        } else {
283cabdff1aSopenharmony_ci            /* Top left is 2 rows back, last pixel */
284cabdff1aSopenharmony_ci            TL = buf[width - (2 * stride) - 1];
285cabdff1aSopenharmony_ci        }
286cabdff1aSopenharmony_ci
287cabdff1aSopenharmony_ci        add_lag_median_prediction(buf, buf - stride, buf,
288cabdff1aSopenharmony_ci                                  width, &L, &TL);
289cabdff1aSopenharmony_ci    }
290cabdff1aSopenharmony_ci}
291cabdff1aSopenharmony_ci
292cabdff1aSopenharmony_cistatic void lag_pred_line_yuy2(LagarithContext *l, uint8_t *buf,
293cabdff1aSopenharmony_ci                               int width, int stride, int line,
294cabdff1aSopenharmony_ci                               int is_luma)
295cabdff1aSopenharmony_ci{
296cabdff1aSopenharmony_ci    int L, TL;
297cabdff1aSopenharmony_ci
298cabdff1aSopenharmony_ci    if (!line) {
299cabdff1aSopenharmony_ci        L= buf[0];
300cabdff1aSopenharmony_ci        if (is_luma)
301cabdff1aSopenharmony_ci            buf[0] = 0;
302cabdff1aSopenharmony_ci        l->llviddsp.add_left_pred(buf, buf, width, 0);
303cabdff1aSopenharmony_ci        if (is_luma)
304cabdff1aSopenharmony_ci            buf[0] = L;
305cabdff1aSopenharmony_ci        return;
306cabdff1aSopenharmony_ci    }
307cabdff1aSopenharmony_ci    if (line == 1) {
308cabdff1aSopenharmony_ci        const int HEAD = is_luma ? 4 : 2;
309cabdff1aSopenharmony_ci        int i;
310cabdff1aSopenharmony_ci
311cabdff1aSopenharmony_ci        L  = buf[width - stride - 1];
312cabdff1aSopenharmony_ci        TL = buf[HEAD  - stride - 1];
313cabdff1aSopenharmony_ci        for (i = 0; i < HEAD; i++) {
314cabdff1aSopenharmony_ci            L += buf[i];
315cabdff1aSopenharmony_ci            buf[i] = L;
316cabdff1aSopenharmony_ci        }
317cabdff1aSopenharmony_ci        for (; i < width; i++) {
318cabdff1aSopenharmony_ci            L      = mid_pred(L & 0xFF, buf[i - stride], (L + buf[i - stride] - TL) & 0xFF) + buf[i];
319cabdff1aSopenharmony_ci            TL     = buf[i - stride];
320cabdff1aSopenharmony_ci            buf[i] = L;
321cabdff1aSopenharmony_ci        }
322cabdff1aSopenharmony_ci    } else {
323cabdff1aSopenharmony_ci        TL = buf[width - (2 * stride) - 1];
324cabdff1aSopenharmony_ci        L  = buf[width - stride - 1];
325cabdff1aSopenharmony_ci        l->llviddsp.add_median_pred(buf, buf - stride, buf, width, &L, &TL);
326cabdff1aSopenharmony_ci    }
327cabdff1aSopenharmony_ci}
328cabdff1aSopenharmony_ci
329cabdff1aSopenharmony_cistatic int lag_decode_line(LagarithContext *l, lag_rac *rac,
330cabdff1aSopenharmony_ci                           uint8_t *dst, int width, int stride,
331cabdff1aSopenharmony_ci                           int esc_count)
332cabdff1aSopenharmony_ci{
333cabdff1aSopenharmony_ci    int i = 0;
334cabdff1aSopenharmony_ci    int ret = 0;
335cabdff1aSopenharmony_ci
336cabdff1aSopenharmony_ci    if (!esc_count)
337cabdff1aSopenharmony_ci        esc_count = -1;
338cabdff1aSopenharmony_ci
339cabdff1aSopenharmony_ci    /* Output any zeros remaining from the previous run */
340cabdff1aSopenharmony_cihandle_zeros:
341cabdff1aSopenharmony_ci    if (l->zeros_rem) {
342cabdff1aSopenharmony_ci        int count = FFMIN(l->zeros_rem, width - i);
343cabdff1aSopenharmony_ci        memset(dst + i, 0, count);
344cabdff1aSopenharmony_ci        i += count;
345cabdff1aSopenharmony_ci        l->zeros_rem -= count;
346cabdff1aSopenharmony_ci    }
347cabdff1aSopenharmony_ci
348cabdff1aSopenharmony_ci    while (i < width) {
349cabdff1aSopenharmony_ci        dst[i] = lag_get_rac(rac);
350cabdff1aSopenharmony_ci        ret++;
351cabdff1aSopenharmony_ci
352cabdff1aSopenharmony_ci        if (dst[i])
353cabdff1aSopenharmony_ci            l->zeros = 0;
354cabdff1aSopenharmony_ci        else
355cabdff1aSopenharmony_ci            l->zeros++;
356cabdff1aSopenharmony_ci
357cabdff1aSopenharmony_ci        i++;
358cabdff1aSopenharmony_ci        if (l->zeros == esc_count) {
359cabdff1aSopenharmony_ci            int index = lag_get_rac(rac);
360cabdff1aSopenharmony_ci            ret++;
361cabdff1aSopenharmony_ci
362cabdff1aSopenharmony_ci            l->zeros = 0;
363cabdff1aSopenharmony_ci
364cabdff1aSopenharmony_ci            l->zeros_rem = lag_calc_zero_run(index);
365cabdff1aSopenharmony_ci            goto handle_zeros;
366cabdff1aSopenharmony_ci        }
367cabdff1aSopenharmony_ci    }
368cabdff1aSopenharmony_ci    return ret;
369cabdff1aSopenharmony_ci}
370cabdff1aSopenharmony_ci
371cabdff1aSopenharmony_cistatic int lag_decode_zero_run_line(LagarithContext *l, uint8_t *dst,
372cabdff1aSopenharmony_ci                                    const uint8_t *src, const uint8_t *src_end,
373cabdff1aSopenharmony_ci                                    int width, int esc_count)
374cabdff1aSopenharmony_ci{
375cabdff1aSopenharmony_ci    int i = 0;
376cabdff1aSopenharmony_ci    int count;
377cabdff1aSopenharmony_ci    uint8_t zero_run = 0;
378cabdff1aSopenharmony_ci    const uint8_t *src_start = src;
379cabdff1aSopenharmony_ci    uint8_t mask1 = -(esc_count < 2);
380cabdff1aSopenharmony_ci    uint8_t mask2 = -(esc_count < 3);
381cabdff1aSopenharmony_ci    uint8_t *end = dst + (width - 2);
382cabdff1aSopenharmony_ci
383cabdff1aSopenharmony_ci    avpriv_request_sample(l->avctx, "zero_run_line");
384cabdff1aSopenharmony_ci
385cabdff1aSopenharmony_ci    memset(dst, 0, width);
386cabdff1aSopenharmony_ci
387cabdff1aSopenharmony_cioutput_zeros:
388cabdff1aSopenharmony_ci    if (l->zeros_rem) {
389cabdff1aSopenharmony_ci        count = FFMIN(l->zeros_rem, width - i);
390cabdff1aSopenharmony_ci        if (end - dst < count) {
391cabdff1aSopenharmony_ci            av_log(l->avctx, AV_LOG_ERROR, "Too many zeros remaining.\n");
392cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
393cabdff1aSopenharmony_ci        }
394cabdff1aSopenharmony_ci
395cabdff1aSopenharmony_ci        memset(dst, 0, count);
396cabdff1aSopenharmony_ci        l->zeros_rem -= count;
397cabdff1aSopenharmony_ci        dst += count;
398cabdff1aSopenharmony_ci    }
399cabdff1aSopenharmony_ci
400cabdff1aSopenharmony_ci    while (dst < end) {
401cabdff1aSopenharmony_ci        i = 0;
402cabdff1aSopenharmony_ci        while (!zero_run && dst + i < end) {
403cabdff1aSopenharmony_ci            i++;
404cabdff1aSopenharmony_ci            if (i+2 >= src_end - src)
405cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
406cabdff1aSopenharmony_ci            zero_run =
407cabdff1aSopenharmony_ci                !(src[i] | (src[i + 1] & mask1) | (src[i + 2] & mask2));
408cabdff1aSopenharmony_ci        }
409cabdff1aSopenharmony_ci        if (zero_run) {
410cabdff1aSopenharmony_ci            zero_run = 0;
411cabdff1aSopenharmony_ci            i += esc_count;
412cabdff1aSopenharmony_ci            if (i >  end - dst ||
413cabdff1aSopenharmony_ci                i >= src_end - src)
414cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
415cabdff1aSopenharmony_ci            memcpy(dst, src, i);
416cabdff1aSopenharmony_ci            dst += i;
417cabdff1aSopenharmony_ci            l->zeros_rem = lag_calc_zero_run(src[i]);
418cabdff1aSopenharmony_ci
419cabdff1aSopenharmony_ci            src += i + 1;
420cabdff1aSopenharmony_ci            goto output_zeros;
421cabdff1aSopenharmony_ci        } else {
422cabdff1aSopenharmony_ci            memcpy(dst, src, i);
423cabdff1aSopenharmony_ci            src += i;
424cabdff1aSopenharmony_ci            dst += i;
425cabdff1aSopenharmony_ci        }
426cabdff1aSopenharmony_ci    }
427cabdff1aSopenharmony_ci    return  src - src_start;
428cabdff1aSopenharmony_ci}
429cabdff1aSopenharmony_ci
430cabdff1aSopenharmony_ci
431cabdff1aSopenharmony_ci
432cabdff1aSopenharmony_cistatic int lag_decode_arith_plane(LagarithContext *l, uint8_t *dst,
433cabdff1aSopenharmony_ci                                  int width, int height, int stride,
434cabdff1aSopenharmony_ci                                  const uint8_t *src, int src_size)
435cabdff1aSopenharmony_ci{
436cabdff1aSopenharmony_ci    int i = 0;
437cabdff1aSopenharmony_ci    int read = 0;
438cabdff1aSopenharmony_ci    uint32_t length;
439cabdff1aSopenharmony_ci    uint32_t offset = 1;
440cabdff1aSopenharmony_ci    int esc_count;
441cabdff1aSopenharmony_ci    GetBitContext gb;
442cabdff1aSopenharmony_ci    lag_rac rac;
443cabdff1aSopenharmony_ci    const uint8_t *src_end = src + src_size;
444cabdff1aSopenharmony_ci    int ret;
445cabdff1aSopenharmony_ci
446cabdff1aSopenharmony_ci    rac.avctx = l->avctx;
447cabdff1aSopenharmony_ci    l->zeros = 0;
448cabdff1aSopenharmony_ci
449cabdff1aSopenharmony_ci    if(src_size < 2)
450cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
451cabdff1aSopenharmony_ci
452cabdff1aSopenharmony_ci    esc_count = src[0];
453cabdff1aSopenharmony_ci    if (esc_count < 4) {
454cabdff1aSopenharmony_ci        length = width * height;
455cabdff1aSopenharmony_ci        if(src_size < 5)
456cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
457cabdff1aSopenharmony_ci        if (esc_count && AV_RL32(src + 1) < length) {
458cabdff1aSopenharmony_ci            length = AV_RL32(src + 1);
459cabdff1aSopenharmony_ci            offset += 4;
460cabdff1aSopenharmony_ci        }
461cabdff1aSopenharmony_ci
462cabdff1aSopenharmony_ci        if ((ret = init_get_bits8(&gb, src + offset, src_size - offset)) < 0)
463cabdff1aSopenharmony_ci            return ret;
464cabdff1aSopenharmony_ci
465cabdff1aSopenharmony_ci        if ((ret = lag_read_prob_header(&rac, &gb)) < 0)
466cabdff1aSopenharmony_ci            return ret;
467cabdff1aSopenharmony_ci
468cabdff1aSopenharmony_ci        ff_lag_rac_init(&rac, &gb, length - stride);
469cabdff1aSopenharmony_ci        for (i = 0; i < height; i++) {
470cabdff1aSopenharmony_ci            if (rac.overread > MAX_OVERREAD)
471cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
472cabdff1aSopenharmony_ci            read += lag_decode_line(l, &rac, dst + (i * stride), width,
473cabdff1aSopenharmony_ci                                    stride, esc_count);
474cabdff1aSopenharmony_ci        }
475cabdff1aSopenharmony_ci
476cabdff1aSopenharmony_ci        if (read > length)
477cabdff1aSopenharmony_ci            av_log(l->avctx, AV_LOG_WARNING,
478cabdff1aSopenharmony_ci                   "Output more bytes than length (%d of %"PRIu32")\n", read,
479cabdff1aSopenharmony_ci                   length);
480cabdff1aSopenharmony_ci    } else if (esc_count < 8) {
481cabdff1aSopenharmony_ci        esc_count -= 4;
482cabdff1aSopenharmony_ci        src ++;
483cabdff1aSopenharmony_ci        src_size --;
484cabdff1aSopenharmony_ci        if (esc_count > 0) {
485cabdff1aSopenharmony_ci            /* Zero run coding only, no range coding. */
486cabdff1aSopenharmony_ci            for (i = 0; i < height; i++) {
487cabdff1aSopenharmony_ci                int res = lag_decode_zero_run_line(l, dst + (i * stride), src,
488cabdff1aSopenharmony_ci                                                   src_end, width, esc_count);
489cabdff1aSopenharmony_ci                if (res < 0)
490cabdff1aSopenharmony_ci                    return res;
491cabdff1aSopenharmony_ci                src += res;
492cabdff1aSopenharmony_ci            }
493cabdff1aSopenharmony_ci        } else {
494cabdff1aSopenharmony_ci            if (src_size < width * height)
495cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA; // buffer not big enough
496cabdff1aSopenharmony_ci            /* Plane is stored uncompressed */
497cabdff1aSopenharmony_ci            for (i = 0; i < height; i++) {
498cabdff1aSopenharmony_ci                memcpy(dst + (i * stride), src, width);
499cabdff1aSopenharmony_ci                src += width;
500cabdff1aSopenharmony_ci            }
501cabdff1aSopenharmony_ci        }
502cabdff1aSopenharmony_ci    } else if (esc_count == 0xff) {
503cabdff1aSopenharmony_ci        /* Plane is a solid run of given value */
504cabdff1aSopenharmony_ci        for (i = 0; i < height; i++)
505cabdff1aSopenharmony_ci            memset(dst + i * stride, src[1], width);
506cabdff1aSopenharmony_ci        /* Do not apply prediction.
507cabdff1aSopenharmony_ci           Note: memset to 0 above, setting first value to src[1]
508cabdff1aSopenharmony_ci           and applying prediction gives the same result. */
509cabdff1aSopenharmony_ci        return 0;
510cabdff1aSopenharmony_ci    } else {
511cabdff1aSopenharmony_ci        av_log(l->avctx, AV_LOG_ERROR,
512cabdff1aSopenharmony_ci               "Invalid zero run escape code! (%#x)\n", esc_count);
513cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
514cabdff1aSopenharmony_ci    }
515cabdff1aSopenharmony_ci
516cabdff1aSopenharmony_ci    if (l->avctx->pix_fmt != AV_PIX_FMT_YUV422P) {
517cabdff1aSopenharmony_ci        for (i = 0; i < height; i++) {
518cabdff1aSopenharmony_ci            lag_pred_line(l, dst, width, stride, i);
519cabdff1aSopenharmony_ci            dst += stride;
520cabdff1aSopenharmony_ci        }
521cabdff1aSopenharmony_ci    } else {
522cabdff1aSopenharmony_ci        for (i = 0; i < height; i++) {
523cabdff1aSopenharmony_ci            lag_pred_line_yuy2(l, dst, width, stride, i,
524cabdff1aSopenharmony_ci                               width == l->avctx->width);
525cabdff1aSopenharmony_ci            dst += stride;
526cabdff1aSopenharmony_ci        }
527cabdff1aSopenharmony_ci    }
528cabdff1aSopenharmony_ci
529cabdff1aSopenharmony_ci    return 0;
530cabdff1aSopenharmony_ci}
531cabdff1aSopenharmony_ci
532cabdff1aSopenharmony_ci/**
533cabdff1aSopenharmony_ci * Decode a frame.
534cabdff1aSopenharmony_ci * @param avctx codec context
535cabdff1aSopenharmony_ci * @param data output AVFrame
536cabdff1aSopenharmony_ci * @param data_size size of output data or 0 if no picture is returned
537cabdff1aSopenharmony_ci * @param avpkt input packet
538cabdff1aSopenharmony_ci * @return number of consumed bytes on success or negative if decode fails
539cabdff1aSopenharmony_ci */
540cabdff1aSopenharmony_cistatic int lag_decode_frame(AVCodecContext *avctx, AVFrame *p,
541cabdff1aSopenharmony_ci                            int *got_frame, AVPacket *avpkt)
542cabdff1aSopenharmony_ci{
543cabdff1aSopenharmony_ci    const uint8_t *buf = avpkt->data;
544cabdff1aSopenharmony_ci    unsigned int buf_size = avpkt->size;
545cabdff1aSopenharmony_ci    LagarithContext *l = avctx->priv_data;
546cabdff1aSopenharmony_ci    uint8_t frametype;
547cabdff1aSopenharmony_ci    uint32_t offset_gu = 0, offset_bv = 0, offset_ry = 9;
548cabdff1aSopenharmony_ci    uint32_t offs[4];
549cabdff1aSopenharmony_ci    uint8_t *srcs[4];
550cabdff1aSopenharmony_ci    int i, j, planes = 3;
551cabdff1aSopenharmony_ci    int ret = 0;
552cabdff1aSopenharmony_ci
553cabdff1aSopenharmony_ci    p->key_frame = 1;
554cabdff1aSopenharmony_ci    p->pict_type = AV_PICTURE_TYPE_I;
555cabdff1aSopenharmony_ci
556cabdff1aSopenharmony_ci    frametype = buf[0];
557cabdff1aSopenharmony_ci
558cabdff1aSopenharmony_ci    offset_gu = AV_RL32(buf + 1);
559cabdff1aSopenharmony_ci    offset_bv = AV_RL32(buf + 5);
560cabdff1aSopenharmony_ci
561cabdff1aSopenharmony_ci    switch (frametype) {
562cabdff1aSopenharmony_ci    case FRAME_SOLID_RGBA:
563cabdff1aSopenharmony_ci        avctx->pix_fmt = AV_PIX_FMT_GBRAP;
564cabdff1aSopenharmony_ci    case FRAME_SOLID_GRAY:
565cabdff1aSopenharmony_ci        if (frametype == FRAME_SOLID_GRAY)
566cabdff1aSopenharmony_ci            if (avctx->bits_per_coded_sample == 24) {
567cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_GBRP;
568cabdff1aSopenharmony_ci            } else {
569cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_GBRAP;
570cabdff1aSopenharmony_ci                planes = 4;
571cabdff1aSopenharmony_ci            }
572cabdff1aSopenharmony_ci
573cabdff1aSopenharmony_ci        if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0)
574cabdff1aSopenharmony_ci            return ret;
575cabdff1aSopenharmony_ci
576cabdff1aSopenharmony_ci        if (frametype == FRAME_SOLID_RGBA) {
577cabdff1aSopenharmony_ci            for (i = 0; i < avctx->height; i++) {
578cabdff1aSopenharmony_ci                memset(p->data[0] + i * p->linesize[0], buf[2], avctx->width);
579cabdff1aSopenharmony_ci                memset(p->data[1] + i * p->linesize[1], buf[1], avctx->width);
580cabdff1aSopenharmony_ci                memset(p->data[2] + i * p->linesize[2], buf[3], avctx->width);
581cabdff1aSopenharmony_ci                memset(p->data[3] + i * p->linesize[3], buf[4], avctx->width);
582cabdff1aSopenharmony_ci            }
583cabdff1aSopenharmony_ci        } else {
584cabdff1aSopenharmony_ci            for (i = 0; i < avctx->height; i++) {
585cabdff1aSopenharmony_ci                for (j = 0; j < planes; j++)
586cabdff1aSopenharmony_ci                    memset(p->data[j] + i * p->linesize[j], buf[1], avctx->width);
587cabdff1aSopenharmony_ci            }
588cabdff1aSopenharmony_ci        }
589cabdff1aSopenharmony_ci        break;
590cabdff1aSopenharmony_ci    case FRAME_SOLID_COLOR:
591cabdff1aSopenharmony_ci        if (avctx->bits_per_coded_sample == 24) {
592cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_GBRP;
593cabdff1aSopenharmony_ci        } else {
594cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_GBRAP;
595cabdff1aSopenharmony_ci        }
596cabdff1aSopenharmony_ci
597cabdff1aSopenharmony_ci        if ((ret = ff_thread_get_buffer(avctx, p,0)) < 0)
598cabdff1aSopenharmony_ci            return ret;
599cabdff1aSopenharmony_ci
600cabdff1aSopenharmony_ci        for (i = 0; i < avctx->height; i++) {
601cabdff1aSopenharmony_ci            memset(p->data[0] + i * p->linesize[0], buf[2], avctx->width);
602cabdff1aSopenharmony_ci            memset(p->data[1] + i * p->linesize[1], buf[1], avctx->width);
603cabdff1aSopenharmony_ci            memset(p->data[2] + i * p->linesize[2], buf[3], avctx->width);
604cabdff1aSopenharmony_ci            if (avctx->pix_fmt == AV_PIX_FMT_GBRAP)
605cabdff1aSopenharmony_ci                memset(p->data[3] + i * p->linesize[3], 0xFFu, avctx->width);
606cabdff1aSopenharmony_ci        }
607cabdff1aSopenharmony_ci        break;
608cabdff1aSopenharmony_ci    case FRAME_ARITH_RGBA:
609cabdff1aSopenharmony_ci        avctx->pix_fmt = AV_PIX_FMT_GBRAP;
610cabdff1aSopenharmony_ci        planes = 4;
611cabdff1aSopenharmony_ci        offset_ry += 4;
612cabdff1aSopenharmony_ci        offs[3] = AV_RL32(buf + 9);
613cabdff1aSopenharmony_ci    case FRAME_ARITH_RGB24:
614cabdff1aSopenharmony_ci    case FRAME_U_RGB24:
615cabdff1aSopenharmony_ci        if (frametype == FRAME_ARITH_RGB24 || frametype == FRAME_U_RGB24)
616cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_GBRP;
617cabdff1aSopenharmony_ci
618cabdff1aSopenharmony_ci        if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0)
619cabdff1aSopenharmony_ci            return ret;
620cabdff1aSopenharmony_ci
621cabdff1aSopenharmony_ci        offs[0] = offset_bv;
622cabdff1aSopenharmony_ci        offs[1] = offset_gu;
623cabdff1aSopenharmony_ci        offs[2] = offset_ry;
624cabdff1aSopenharmony_ci
625cabdff1aSopenharmony_ci        for (i = 0; i < planes; i++)
626cabdff1aSopenharmony_ci            srcs[i] = p->data[i] + (avctx->height - 1) * p->linesize[i];
627cabdff1aSopenharmony_ci        for (i = 0; i < planes; i++)
628cabdff1aSopenharmony_ci            if (buf_size <= offs[i]) {
629cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR,
630cabdff1aSopenharmony_ci                        "Invalid frame offsets\n");
631cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
632cabdff1aSopenharmony_ci            }
633cabdff1aSopenharmony_ci
634cabdff1aSopenharmony_ci        for (i = 0; i < planes; i++) {
635cabdff1aSopenharmony_ci            ret = lag_decode_arith_plane(l, srcs[i],
636cabdff1aSopenharmony_ci                                   avctx->width, avctx->height,
637cabdff1aSopenharmony_ci                                   -p->linesize[i], buf + offs[i],
638cabdff1aSopenharmony_ci                                   buf_size - offs[i]);
639cabdff1aSopenharmony_ci            if (ret < 0)
640cabdff1aSopenharmony_ci                return ret;
641cabdff1aSopenharmony_ci        }
642cabdff1aSopenharmony_ci        for (i = 0; i < avctx->height; i++) {
643cabdff1aSopenharmony_ci            l->llviddsp.add_bytes(p->data[0] + i * p->linesize[0], p->data[1] + i * p->linesize[1], avctx->width);
644cabdff1aSopenharmony_ci            l->llviddsp.add_bytes(p->data[2] + i * p->linesize[2], p->data[1] + i * p->linesize[1], avctx->width);
645cabdff1aSopenharmony_ci        }
646cabdff1aSopenharmony_ci        FFSWAP(uint8_t*, p->data[0], p->data[1]);
647cabdff1aSopenharmony_ci        FFSWAP(int, p->linesize[0], p->linesize[1]);
648cabdff1aSopenharmony_ci        FFSWAP(uint8_t*, p->data[2], p->data[1]);
649cabdff1aSopenharmony_ci        FFSWAP(int, p->linesize[2], p->linesize[1]);
650cabdff1aSopenharmony_ci        break;
651cabdff1aSopenharmony_ci    case FRAME_ARITH_YUY2:
652cabdff1aSopenharmony_ci        avctx->pix_fmt = AV_PIX_FMT_YUV422P;
653cabdff1aSopenharmony_ci
654cabdff1aSopenharmony_ci        if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0)
655cabdff1aSopenharmony_ci            return ret;
656cabdff1aSopenharmony_ci
657cabdff1aSopenharmony_ci        if (offset_ry >= buf_size ||
658cabdff1aSopenharmony_ci            offset_gu >= buf_size ||
659cabdff1aSopenharmony_ci            offset_bv >= buf_size) {
660cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
661cabdff1aSopenharmony_ci                   "Invalid frame offsets\n");
662cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
663cabdff1aSopenharmony_ci        }
664cabdff1aSopenharmony_ci
665cabdff1aSopenharmony_ci        ret = lag_decode_arith_plane(l, p->data[0], avctx->width, avctx->height,
666cabdff1aSopenharmony_ci                               p->linesize[0], buf + offset_ry,
667cabdff1aSopenharmony_ci                               buf_size - offset_ry);
668cabdff1aSopenharmony_ci        if (ret < 0)
669cabdff1aSopenharmony_ci            return ret;
670cabdff1aSopenharmony_ci        ret = lag_decode_arith_plane(l, p->data[1], (avctx->width + 1) / 2,
671cabdff1aSopenharmony_ci                               avctx->height, p->linesize[1],
672cabdff1aSopenharmony_ci                               buf + offset_gu, buf_size - offset_gu);
673cabdff1aSopenharmony_ci        if (ret < 0)
674cabdff1aSopenharmony_ci            return ret;
675cabdff1aSopenharmony_ci        ret = lag_decode_arith_plane(l, p->data[2], (avctx->width + 1) / 2,
676cabdff1aSopenharmony_ci                               avctx->height, p->linesize[2],
677cabdff1aSopenharmony_ci                               buf + offset_bv, buf_size - offset_bv);
678cabdff1aSopenharmony_ci        break;
679cabdff1aSopenharmony_ci    case FRAME_ARITH_YV12:
680cabdff1aSopenharmony_ci        avctx->pix_fmt = AV_PIX_FMT_YUV420P;
681cabdff1aSopenharmony_ci
682cabdff1aSopenharmony_ci        if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0)
683cabdff1aSopenharmony_ci            return ret;
684cabdff1aSopenharmony_ci
685cabdff1aSopenharmony_ci        if (offset_ry >= buf_size ||
686cabdff1aSopenharmony_ci            offset_gu >= buf_size ||
687cabdff1aSopenharmony_ci            offset_bv >= buf_size) {
688cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
689cabdff1aSopenharmony_ci                   "Invalid frame offsets\n");
690cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
691cabdff1aSopenharmony_ci        }
692cabdff1aSopenharmony_ci
693cabdff1aSopenharmony_ci        ret = lag_decode_arith_plane(l, p->data[0], avctx->width, avctx->height,
694cabdff1aSopenharmony_ci                               p->linesize[0], buf + offset_ry,
695cabdff1aSopenharmony_ci                               buf_size - offset_ry);
696cabdff1aSopenharmony_ci        if (ret < 0)
697cabdff1aSopenharmony_ci            return ret;
698cabdff1aSopenharmony_ci        ret = lag_decode_arith_plane(l, p->data[2], (avctx->width + 1) / 2,
699cabdff1aSopenharmony_ci                               (avctx->height + 1) / 2, p->linesize[2],
700cabdff1aSopenharmony_ci                               buf + offset_gu, buf_size - offset_gu);
701cabdff1aSopenharmony_ci        if (ret < 0)
702cabdff1aSopenharmony_ci            return ret;
703cabdff1aSopenharmony_ci        ret = lag_decode_arith_plane(l, p->data[1], (avctx->width + 1) / 2,
704cabdff1aSopenharmony_ci                               (avctx->height + 1) / 2, p->linesize[1],
705cabdff1aSopenharmony_ci                               buf + offset_bv, buf_size - offset_bv);
706cabdff1aSopenharmony_ci        break;
707cabdff1aSopenharmony_ci    default:
708cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
709cabdff1aSopenharmony_ci               "Unsupported Lagarith frame type: %#"PRIx8"\n", frametype);
710cabdff1aSopenharmony_ci        return AVERROR_PATCHWELCOME;
711cabdff1aSopenharmony_ci    }
712cabdff1aSopenharmony_ci
713cabdff1aSopenharmony_ci    if (ret < 0)
714cabdff1aSopenharmony_ci        return ret;
715cabdff1aSopenharmony_ci
716cabdff1aSopenharmony_ci    *got_frame = 1;
717cabdff1aSopenharmony_ci
718cabdff1aSopenharmony_ci    return buf_size;
719cabdff1aSopenharmony_ci}
720cabdff1aSopenharmony_ci
721cabdff1aSopenharmony_cistatic av_cold int lag_decode_init(AVCodecContext *avctx)
722cabdff1aSopenharmony_ci{
723cabdff1aSopenharmony_ci    LagarithContext *l = avctx->priv_data;
724cabdff1aSopenharmony_ci    l->avctx = avctx;
725cabdff1aSopenharmony_ci
726cabdff1aSopenharmony_ci    ff_llviddsp_init(&l->llviddsp);
727cabdff1aSopenharmony_ci
728cabdff1aSopenharmony_ci    return 0;
729cabdff1aSopenharmony_ci}
730cabdff1aSopenharmony_ci
731cabdff1aSopenharmony_ciconst FFCodec ff_lagarith_decoder = {
732cabdff1aSopenharmony_ci    .p.name         = "lagarith",
733cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Lagarith lossless"),
734cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
735cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_LAGARITH,
736cabdff1aSopenharmony_ci    .priv_data_size = sizeof(LagarithContext),
737cabdff1aSopenharmony_ci    .init           = lag_decode_init,
738cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(lag_decode_frame),
739cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
740cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
741cabdff1aSopenharmony_ci};
742