xref: /third_party/ffmpeg/libavcodec/ylc.c (revision cabdff1a)
1/*
2 * YUY2 Lossless Codec
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#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#define YLC_VLC_BITS 10
26
27#include "libavutil/imgutils.h"
28#include "libavutil/internal.h"
29#include "libavutil/intreadwrite.h"
30#include "libavutil/mem.h"
31#include "avcodec.h"
32#include "bswapdsp.h"
33#include "codec_internal.h"
34#include "get_bits.h"
35#include "huffyuvdsp.h"
36#include "thread.h"
37#include "unary.h"
38
39typedef struct YLCContext {
40    VLC vlc[4];
41    uint32_t table[256];
42    uint8_t *buffer;
43    int buffer_size;
44    BswapDSPContext bdsp;
45} YLCContext;
46
47static av_cold int decode_init(AVCodecContext *avctx)
48{
49    YLCContext *s = avctx->priv_data;
50
51    avctx->pix_fmt = AV_PIX_FMT_YUYV422;
52    ff_bswapdsp_init(&s->bdsp);
53
54    return 0;
55}
56
57typedef struct Node {
58    int16_t  sym;
59    uint32_t count;
60    int16_t  l, r;
61} Node;
62
63static void get_tree_codes(uint32_t *bits, int16_t *lens, uint8_t *xlat,
64                           Node *nodes, int node,
65                           uint32_t pfx, int pl, int *pos)
66{
67    int s;
68
69    s = nodes[node].sym;
70    if (s != -1) {
71        bits[*pos] = (~pfx) & ((1ULL << FFMAX(pl, 1)) - 1);
72        lens[*pos] = FFMAX(pl, 1);
73        xlat[*pos] = s + (pl == 0);
74        (*pos)++;
75    } else {
76        pfx <<= 1;
77        pl++;
78        get_tree_codes(bits, lens, xlat, nodes, nodes[node].l, pfx, pl,
79                       pos);
80        pfx |= 1;
81        get_tree_codes(bits, lens, xlat, nodes, nodes[node].r, pfx, pl,
82                       pos);
83    }
84}
85
86static int build_vlc(AVCodecContext *avctx, VLC *vlc, const uint32_t *table)
87{
88    Node nodes[512];
89    uint32_t bits[256];
90    int16_t lens[256];
91    uint8_t xlat[256];
92    int cur_node, i, j, pos = 0;
93
94    ff_free_vlc(vlc);
95
96    for (i = 0; i < 256; i++) {
97        nodes[i].count = table[i];
98        nodes[i].sym   = i;
99        nodes[i].l     = i;
100        nodes[i].r     = i;
101    }
102
103    cur_node = 256;
104    j = 0;
105    do {
106        for (i = 0; ; i++) {
107            int new_node = j;
108            int first_node = cur_node;
109            int second_node = cur_node;
110            unsigned nd, st;
111
112            nodes[cur_node].count = -1;
113
114            do {
115                int val = nodes[new_node].count;
116                if (val && (val < nodes[first_node].count)) {
117                    if (val >= nodes[second_node].count) {
118                        first_node = new_node;
119                    } else {
120                        first_node = second_node;
121                        second_node = new_node;
122                    }
123                }
124                new_node += 1;
125            } while (new_node != cur_node);
126
127            if (first_node == cur_node)
128                break;
129
130            nd = nodes[second_node].count;
131            st = nodes[first_node].count;
132            nodes[second_node].count = 0;
133            nodes[first_node].count  = 0;
134            if (nd >= UINT32_MAX - st) {
135                av_log(avctx, AV_LOG_ERROR, "count overflow\n");
136                return AVERROR_INVALIDDATA;
137            }
138            nodes[cur_node].count = nd + st;
139            nodes[cur_node].sym = -1;
140            nodes[cur_node].l = first_node;
141            nodes[cur_node].r = second_node;
142            cur_node++;
143        }
144        j++;
145    } while (cur_node - 256 == j);
146
147    get_tree_codes(bits, lens, xlat, nodes, cur_node - 1, 0, 0, &pos);
148
149    return ff_init_vlc_sparse(vlc, YLC_VLC_BITS, pos, lens, 2, 2,
150                              bits, 4, 4, xlat, 1, 1, 0);
151}
152
153static const uint8_t table_y1[] = {
154    0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
155    0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
156    0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
157    0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
158    0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
159    0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF,
160    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
161    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
162    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
163    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
164    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
165    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
168    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
171    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
172    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
173    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
174    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
175    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
176    0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
177    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
178    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
179    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
180    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
181    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
182    0x02, 0x00,
183};
184
185static const uint8_t table_u[] = {
186    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
187    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
188    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
190    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
191    0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0xFF,
192    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
193    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
194    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195    0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,
196    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
197    0x01, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
198    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
199    0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
202    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF,
203    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
204    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
205    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
207    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
208    0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0xFF, 0xFF,
209    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
210    0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
211    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
212    0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
213    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
214    0x01, 0x00,
215};
216
217static const uint8_t table_y2[] = {
218    0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE,
219    0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFC,
220    0xFC, 0xFC, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE,
221    0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFC, 0xFC,
222    0xFC, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF,
223    0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFD, 0xFD, 0xFD,
224    0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
225    0x00, 0x01, 0x01, 0x01, 0xFD, 0xFD, 0xFD, 0xFE,
226    0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
227    0x01, 0x01, 0x01, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE,
228    0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
229    0x01, 0x01, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF,
230    0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02,
231    0x02, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0x00,
232    0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
233    0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
234    0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0xFF,
235    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
236    0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0xFF, 0xFF,
237    0xFF, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02,
238    0x02, 0x02, 0x03, 0x03, 0x03, 0xFF, 0xFF, 0xFF,
239    0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02,
240    0x02, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x01,
241    0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
242    0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01,
243    0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04,
244    0x04, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
245    0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04,
246    0x04, 0x00,
247};
248
249static const uint8_t table_v[] = {
250    0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00,
251    0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF,
252    0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01,
253    0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00,
254    0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF,
255    0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01,
256    0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00,
257    0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF,
258    0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01,
259    0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00,
260    0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF,
261    0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01,
262    0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00,
263    0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF,
264    0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01,
265    0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00,
266    0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF,
267    0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01,
268    0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00,
269    0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF,
270    0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01,
271    0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00,
272    0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF,
273    0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01,
274    0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00,
275    0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF,
276    0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01,
277    0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00,
278    0x01, 0x00,
279};
280
281static int decode_frame(AVCodecContext *avctx, AVFrame *p,
282                        int *got_frame, AVPacket *avpkt)
283{
284    int TL[4] = { 128, 128, 128, 128 };
285    int L[4]  = { 128, 128, 128, 128 };
286    YLCContext *s = avctx->priv_data;
287    const uint8_t *buf = avpkt->data;
288    int ret, x, y, toffset, boffset;
289    GetBitContext gb;
290    uint8_t *dst;
291
292    if (avpkt->size <= 16)
293        return AVERROR_INVALIDDATA;
294
295    if (AV_RL32(buf) != MKTAG('Y', 'L', 'C', '0') ||
296        AV_RL32(buf + 4) != 0)
297        return AVERROR_INVALIDDATA;
298
299    toffset = AV_RL32(buf + 8);
300    if (toffset < 16 || toffset >= avpkt->size)
301        return AVERROR_INVALIDDATA;
302
303    boffset = AV_RL32(buf + 12);
304    if (toffset >= boffset || boffset >= avpkt->size)
305        return AVERROR_INVALIDDATA;
306
307    if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0)
308        return ret;
309
310    av_fast_malloc(&s->buffer, &s->buffer_size,
311                   FFMAX(boffset - toffset, avpkt->size - boffset)
312                       + AV_INPUT_BUFFER_PADDING_SIZE);
313    if (!s->buffer)
314        return AVERROR(ENOMEM);
315
316    memcpy(s->buffer, avpkt->data + toffset, boffset - toffset);
317    memset(s->buffer + boffset - toffset, 0, AV_INPUT_BUFFER_PADDING_SIZE);
318    s->bdsp.bswap_buf((uint32_t *) s->buffer,
319                      (uint32_t *) s->buffer,
320                      (boffset - toffset + 3) >> 2);
321    if ((ret = init_get_bits8(&gb, s->buffer, boffset - toffset)) < 0)
322        return ret;
323
324    for (int i = 0; i < 4; i++) {
325        for (x = 0; x < 256; x++) {
326            unsigned len = get_unary(&gb, 1, 31);
327            uint32_t val = ((1U << len) - 1) + get_bits_long(&gb, len);
328
329            s->table[x] = val;
330        }
331
332        ret = build_vlc(avctx, &s->vlc[i], s->table);
333        if (ret < 0)
334            return ret;
335    }
336
337    memcpy(s->buffer, avpkt->data + boffset, avpkt->size - boffset);
338    memset(s->buffer + avpkt->size - boffset, 0, AV_INPUT_BUFFER_PADDING_SIZE);
339    s->bdsp.bswap_buf((uint32_t *) s->buffer,
340                      (uint32_t *) s->buffer,
341                      (avpkt->size - boffset) >> 2);
342    if ((ret = init_get_bits8(&gb, s->buffer, avpkt->size - boffset)) < 0)
343        return ret;
344
345    dst = p->data[0];
346    for (y = 0; y < avctx->height; y++) {
347        memset(dst, 0, avctx->width * 2);
348        dst += p->linesize[0];
349    }
350
351    dst = p->data[0];
352    for (y = 0; y < avctx->height; y++) {
353        for (x = 0; x < avctx->width * 2 && y < avctx->height;) {
354            if (get_bits_left(&gb) <= 0)
355                return AVERROR_INVALIDDATA;
356
357            if (get_bits1(&gb)) {
358                int val = get_vlc2(&gb, s->vlc[0].table, YLC_VLC_BITS, 3);
359                if (val < 0) {
360                    return AVERROR_INVALIDDATA;
361                } else if (val < 0xE1) {
362                    dst[x    ] = table_y1[val];
363                    dst[x + 1] = table_u[val];
364                    dst[x + 2] = table_y2[val];
365                    dst[x + 3] = table_v[val];
366                    x += 4;
367                } else {
368                    int incr = (val - 0xDF) * 4;
369                    if (x + incr >= avctx->width * 2) {
370                        int iy = ((x + incr) / (avctx->width * 2));
371                        x  = (x + incr) % (avctx->width * 2);
372                        y += iy;
373                        dst += iy * p->linesize[0];
374                    } else {
375                        x += incr;
376                    }
377                }
378            } else {
379                int y1, y2, u, v;
380
381                y1 = get_vlc2(&gb, s->vlc[1].table, YLC_VLC_BITS, 3);
382                u  = get_vlc2(&gb, s->vlc[2].table, YLC_VLC_BITS, 3);
383                y2 = get_vlc2(&gb, s->vlc[1].table, YLC_VLC_BITS, 3);
384                v  = get_vlc2(&gb, s->vlc[3].table, YLC_VLC_BITS, 3);
385                if (y1 < 0 || y2 < 0 || u < 0 || v < 0)
386                    return AVERROR_INVALIDDATA;
387                dst[x    ] = y1;
388                dst[x + 1] = u;
389                dst[x + 2] = y1 + y2;
390                dst[x + 3] = v;
391                x += 4;
392            }
393        }
394        dst += p->linesize[0];
395    }
396
397    dst = p->data[0];
398    for (x = 0; x < avctx->width * 2; x += 4) {
399        dst[x    ] =        dst[x    ] + L[0];
400        dst[x + 2] = L[0] = dst[x + 2] + L[0];
401        L[1] = dst[x + 1] + L[1];
402        dst[x + 1] = L[1];
403        L[2] = dst[x + 3] + L[2];
404        dst[x + 3] = L[2];
405    }
406    dst += p->linesize[0];
407
408    for (y = 1; y < avctx->height; y++) {
409        x = 0;
410        dst[x    ] =        dst[x    ] + L[0] + dst[x + 0 - p->linesize[0]] - TL[0];
411        dst[x + 2] = L[0] = dst[x + 2] + L[0] + dst[x + 2 - p->linesize[0]] - TL[0];
412        TL[0] = dst[x + 2 - p->linesize[0]];
413        L[1] = dst[x + 1] + L[1] + dst[x + 1 - p->linesize[0]] - TL[1];
414        dst[x + 1] = L[1];
415        TL[1] = dst[x + 1 - p->linesize[0]];
416        L[2] = dst[x + 3] + L[2] + dst[x + 3 - p->linesize[0]] - TL[2];
417        dst[x + 3] = L[2];
418        TL[2] = dst[x + 3 - p->linesize[0]];
419        for (x = 4; x < avctx->width * 2; x += 4) {
420            dst[x    ] =        dst[x    ] + L[0] + dst[x + 0 - p->linesize[0]] - TL[0];
421            dst[x + 2] = L[0] = dst[x + 2] + L[0] + dst[x + 2 - p->linesize[0]] - TL[0];
422            TL[0] = dst[x + 2 - p->linesize[0]];
423            L[1] = dst[x + 1] + L[1] + dst[x + 1 - p->linesize[0]] - TL[1];
424            dst[x + 1] = L[1];
425            TL[1] = dst[x + 1 - p->linesize[0]];
426            L[2] = dst[x + 3] + L[2] + dst[x + 3 - p->linesize[0]] - TL[2];
427            dst[x + 3] = L[2];
428            TL[2] = dst[x + 3 - p->linesize[0]];
429        }
430        dst += p->linesize[0];
431    }
432
433    p->pict_type = AV_PICTURE_TYPE_I;
434    p->key_frame = 1;
435    *got_frame   = 1;
436
437    return avpkt->size;
438}
439
440static av_cold int decode_end(AVCodecContext *avctx)
441{
442    YLCContext *s = avctx->priv_data;
443
444    for (int i = 0; i < FF_ARRAY_ELEMS(s->vlc); i++)
445        ff_free_vlc(&s->vlc[i]);
446    av_freep(&s->buffer);
447    s->buffer_size = 0;
448
449    return 0;
450}
451
452const FFCodec ff_ylc_decoder = {
453    .p.name         = "ylc",
454    .p.long_name    = NULL_IF_CONFIG_SMALL("YUY2 Lossless Codec"),
455    .p.type         = AVMEDIA_TYPE_VIDEO,
456    .p.id           = AV_CODEC_ID_YLC,
457    .priv_data_size = sizeof(YLCContext),
458    .init           = decode_init,
459    .close          = decode_end,
460    FF_CODEC_DECODE_CB(decode_frame),
461    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
462    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
463};
464