1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Motion Pixels Video Decoder
3cabdff1aSopenharmony_ci * Copyright (c) 2008 Gregory Montoir (cyx@users.sourceforge.net)
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#include "libavutil/thread.h"
23cabdff1aSopenharmony_ci
24cabdff1aSopenharmony_ci#include "config.h"
25cabdff1aSopenharmony_ci
26cabdff1aSopenharmony_ci#include "avcodec.h"
27cabdff1aSopenharmony_ci#include "get_bits.h"
28cabdff1aSopenharmony_ci#include "bswapdsp.h"
29cabdff1aSopenharmony_ci#include "codec_internal.h"
30cabdff1aSopenharmony_ci#include "internal.h"
31cabdff1aSopenharmony_ci
32cabdff1aSopenharmony_ci#define MAX_HUFF_CODES 16
33cabdff1aSopenharmony_ci
34cabdff1aSopenharmony_ci#include "motionpixels_tablegen.h"
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_citypedef struct HuffCode {
37cabdff1aSopenharmony_ci    uint8_t size;
38cabdff1aSopenharmony_ci    uint8_t delta;
39cabdff1aSopenharmony_ci} HuffCode;
40cabdff1aSopenharmony_ci
41cabdff1aSopenharmony_citypedef struct MotionPixelsContext {
42cabdff1aSopenharmony_ci    AVCodecContext *avctx;
43cabdff1aSopenharmony_ci    AVFrame *frame;
44cabdff1aSopenharmony_ci    BswapDSPContext bdsp;
45cabdff1aSopenharmony_ci    uint8_t *changes_map;
46cabdff1aSopenharmony_ci    int offset_bits_len;
47cabdff1aSopenharmony_ci    int codes_count, current_codes_count;
48cabdff1aSopenharmony_ci    int max_codes_bits;
49cabdff1aSopenharmony_ci    HuffCode codes[MAX_HUFF_CODES];
50cabdff1aSopenharmony_ci    VLC vlc;
51cabdff1aSopenharmony_ci    YuvPixel *vpt, *hpt;
52cabdff1aSopenharmony_ci    uint8_t gradient_scale[3];
53cabdff1aSopenharmony_ci    uint8_t *bswapbuf;
54cabdff1aSopenharmony_ci    int bswapbuf_size;
55cabdff1aSopenharmony_ci} MotionPixelsContext;
56cabdff1aSopenharmony_ci
57cabdff1aSopenharmony_cistatic av_cold int mp_decode_end(AVCodecContext *avctx)
58cabdff1aSopenharmony_ci{
59cabdff1aSopenharmony_ci    MotionPixelsContext *mp = avctx->priv_data;
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_ci    av_freep(&mp->changes_map);
62cabdff1aSopenharmony_ci    av_freep(&mp->vpt);
63cabdff1aSopenharmony_ci    av_freep(&mp->hpt);
64cabdff1aSopenharmony_ci    av_freep(&mp->bswapbuf);
65cabdff1aSopenharmony_ci    av_frame_free(&mp->frame);
66cabdff1aSopenharmony_ci
67cabdff1aSopenharmony_ci    return 0;
68cabdff1aSopenharmony_ci}
69cabdff1aSopenharmony_ci
70cabdff1aSopenharmony_cistatic av_cold int mp_decode_init(AVCodecContext *avctx)
71cabdff1aSopenharmony_ci{
72cabdff1aSopenharmony_ci    av_unused static AVOnce init_static_once = AV_ONCE_INIT;
73cabdff1aSopenharmony_ci    MotionPixelsContext *mp = avctx->priv_data;
74cabdff1aSopenharmony_ci    int w4 = (avctx->width  + 3) & ~3;
75cabdff1aSopenharmony_ci    int h4 = (avctx->height + 3) & ~3;
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_ci    if(avctx->extradata_size < 2){
78cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "extradata too small\n");
79cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
80cabdff1aSopenharmony_ci    }
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_ci    mp->avctx = avctx;
83cabdff1aSopenharmony_ci    ff_bswapdsp_init(&mp->bdsp);
84cabdff1aSopenharmony_ci    mp->changes_map = av_calloc(avctx->width, h4);
85cabdff1aSopenharmony_ci    mp->offset_bits_len = av_log2(avctx->width * avctx->height) + 1;
86cabdff1aSopenharmony_ci    mp->vpt = av_calloc(avctx->height, sizeof(*mp->vpt));
87cabdff1aSopenharmony_ci    mp->hpt = av_calloc(h4 / 4, w4 / 4 * sizeof(*mp->hpt));
88cabdff1aSopenharmony_ci    if (!mp->changes_map || !mp->vpt || !mp->hpt)
89cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
90cabdff1aSopenharmony_ci    avctx->pix_fmt = AV_PIX_FMT_RGB555;
91cabdff1aSopenharmony_ci
92cabdff1aSopenharmony_ci    mp->frame = av_frame_alloc();
93cabdff1aSopenharmony_ci    if (!mp->frame)
94cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
95cabdff1aSopenharmony_ci
96cabdff1aSopenharmony_ci#if !CONFIG_HARDCODED_TABLES
97cabdff1aSopenharmony_ci    ff_thread_once(&init_static_once, motionpixels_tableinit);
98cabdff1aSopenharmony_ci#endif
99cabdff1aSopenharmony_ci
100cabdff1aSopenharmony_ci    return 0;
101cabdff1aSopenharmony_ci}
102cabdff1aSopenharmony_ci
103cabdff1aSopenharmony_cistatic void mp_read_changes_map(MotionPixelsContext *mp, GetBitContext *gb, int count, int bits_len, int read_color)
104cabdff1aSopenharmony_ci{
105cabdff1aSopenharmony_ci    uint16_t *pixels;
106cabdff1aSopenharmony_ci    int offset, w, h, color = 0, x, y, i;
107cabdff1aSopenharmony_ci
108cabdff1aSopenharmony_ci    while (count--) {
109cabdff1aSopenharmony_ci        offset = get_bits_long(gb, mp->offset_bits_len);
110cabdff1aSopenharmony_ci        w      = get_bits(gb, bits_len) + 1;
111cabdff1aSopenharmony_ci        h      = get_bits(gb, bits_len) + 1;
112cabdff1aSopenharmony_ci        if (read_color)
113cabdff1aSopenharmony_ci            color = get_bits(gb, 15);
114cabdff1aSopenharmony_ci        x = offset % mp->avctx->width;
115cabdff1aSopenharmony_ci        y = offset / mp->avctx->width;
116cabdff1aSopenharmony_ci        if (y >= mp->avctx->height)
117cabdff1aSopenharmony_ci            continue;
118cabdff1aSopenharmony_ci        w = FFMIN(w, mp->avctx->width  - x);
119cabdff1aSopenharmony_ci        h = FFMIN(h, mp->avctx->height - y);
120cabdff1aSopenharmony_ci        pixels = (uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2];
121cabdff1aSopenharmony_ci        while (h--) {
122cabdff1aSopenharmony_ci            mp->changes_map[offset] = w;
123cabdff1aSopenharmony_ci            if (read_color)
124cabdff1aSopenharmony_ci                for (i = 0; i < w; ++i)
125cabdff1aSopenharmony_ci                    pixels[i] = color;
126cabdff1aSopenharmony_ci            offset += mp->avctx->width;
127cabdff1aSopenharmony_ci            pixels += mp->frame->linesize[0] / 2;
128cabdff1aSopenharmony_ci        }
129cabdff1aSopenharmony_ci    }
130cabdff1aSopenharmony_ci}
131cabdff1aSopenharmony_ci
132cabdff1aSopenharmony_cistatic int mp_get_code(MotionPixelsContext *mp, GetBitContext *gb, int size)
133cabdff1aSopenharmony_ci{
134cabdff1aSopenharmony_ci    while (get_bits1(gb)) {
135cabdff1aSopenharmony_ci        ++size;
136cabdff1aSopenharmony_ci        if (size > mp->max_codes_bits) {
137cabdff1aSopenharmony_ci            av_log(mp->avctx, AV_LOG_ERROR, "invalid code size %d/%d\n", size, mp->max_codes_bits);
138cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
139cabdff1aSopenharmony_ci        }
140cabdff1aSopenharmony_ci        if (mp_get_code(mp, gb, size) < 0)
141cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
142cabdff1aSopenharmony_ci    }
143cabdff1aSopenharmony_ci    if (mp->current_codes_count >= mp->codes_count) {
144cabdff1aSopenharmony_ci        av_log(mp->avctx, AV_LOG_ERROR, "too many codes\n");
145cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
146cabdff1aSopenharmony_ci    }
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci    mp->codes[mp->current_codes_count++].size = size;
149cabdff1aSopenharmony_ci    return 0;
150cabdff1aSopenharmony_ci}
151cabdff1aSopenharmony_ci
152cabdff1aSopenharmony_cistatic int mp_read_codes_table(MotionPixelsContext *mp, GetBitContext *gb)
153cabdff1aSopenharmony_ci{
154cabdff1aSopenharmony_ci    if (mp->codes_count == 1) {
155cabdff1aSopenharmony_ci        mp->codes[0].delta = get_bits(gb, 4);
156cabdff1aSopenharmony_ci    } else {
157cabdff1aSopenharmony_ci        int i;
158cabdff1aSopenharmony_ci        int ret;
159cabdff1aSopenharmony_ci
160cabdff1aSopenharmony_ci        mp->max_codes_bits = get_bits(gb, 4);
161cabdff1aSopenharmony_ci        for (i = 0; i < mp->codes_count; ++i)
162cabdff1aSopenharmony_ci            mp->codes[i].delta = get_bits(gb, 4);
163cabdff1aSopenharmony_ci        mp->current_codes_count = 0;
164cabdff1aSopenharmony_ci        if ((ret = mp_get_code(mp, gb, 0)) < 0)
165cabdff1aSopenharmony_ci            return ret;
166cabdff1aSopenharmony_ci        if (mp->current_codes_count < mp->codes_count) {
167cabdff1aSopenharmony_ci            av_log(mp->avctx, AV_LOG_ERROR, "too few codes\n");
168cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
169cabdff1aSopenharmony_ci        }
170cabdff1aSopenharmony_ci   }
171cabdff1aSopenharmony_ci   return 0;
172cabdff1aSopenharmony_ci}
173cabdff1aSopenharmony_ci
174cabdff1aSopenharmony_cistatic av_always_inline int mp_gradient(MotionPixelsContext *mp, int component, int v)
175cabdff1aSopenharmony_ci{
176cabdff1aSopenharmony_ci    int delta;
177cabdff1aSopenharmony_ci
178cabdff1aSopenharmony_ci    delta = (v - 7) * mp->gradient_scale[component];
179cabdff1aSopenharmony_ci    mp->gradient_scale[component] = (v == 0 || v == 14) ? 2 : 1;
180cabdff1aSopenharmony_ci    return delta;
181cabdff1aSopenharmony_ci}
182cabdff1aSopenharmony_ci
183cabdff1aSopenharmony_cistatic YuvPixel mp_get_yuv_from_rgb(MotionPixelsContext *mp, int x, int y)
184cabdff1aSopenharmony_ci{
185cabdff1aSopenharmony_ci    int color;
186cabdff1aSopenharmony_ci
187cabdff1aSopenharmony_ci    color = *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2];
188cabdff1aSopenharmony_ci    return mp_rgb_yuv_table[color & 0x7FFF];
189cabdff1aSopenharmony_ci}
190cabdff1aSopenharmony_ci
191cabdff1aSopenharmony_cistatic void mp_set_rgb_from_yuv(MotionPixelsContext *mp, int x, int y, const YuvPixel *p)
192cabdff1aSopenharmony_ci{
193cabdff1aSopenharmony_ci    int color;
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci    color = mp_yuv_to_rgb(p->y, p->v, p->u, 1);
196cabdff1aSopenharmony_ci    *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2] = color;
197cabdff1aSopenharmony_ci}
198cabdff1aSopenharmony_ci
199cabdff1aSopenharmony_cistatic av_always_inline int mp_get_vlc(MotionPixelsContext *mp, GetBitContext *gb)
200cabdff1aSopenharmony_ci{
201cabdff1aSopenharmony_ci    return mp->vlc.table ? get_vlc2(gb, mp->vlc.table, mp->max_codes_bits, 1)
202cabdff1aSopenharmony_ci                         : mp->codes[0].delta;
203cabdff1aSopenharmony_ci}
204cabdff1aSopenharmony_ci
205cabdff1aSopenharmony_cistatic void mp_decode_line(MotionPixelsContext *mp, GetBitContext *gb, int y)
206cabdff1aSopenharmony_ci{
207cabdff1aSopenharmony_ci    YuvPixel p;
208cabdff1aSopenharmony_ci    const int y0 = y * mp->avctx->width;
209cabdff1aSopenharmony_ci    int w, i, x = 0;
210cabdff1aSopenharmony_ci
211cabdff1aSopenharmony_ci    p = mp->vpt[y];
212cabdff1aSopenharmony_ci    if (mp->changes_map[y0 + x] == 0) {
213cabdff1aSopenharmony_ci        memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
214cabdff1aSopenharmony_ci        ++x;
215cabdff1aSopenharmony_ci    }
216cabdff1aSopenharmony_ci    while (x < mp->avctx->width) {
217cabdff1aSopenharmony_ci        w = mp->changes_map[y0 + x];
218cabdff1aSopenharmony_ci        if (w != 0) {
219cabdff1aSopenharmony_ci            if ((y & 3) == 0) {
220cabdff1aSopenharmony_ci                if (mp->changes_map[y0 + x + mp->avctx->width] < w ||
221cabdff1aSopenharmony_ci                    mp->changes_map[y0 + x + mp->avctx->width * 2] < w ||
222cabdff1aSopenharmony_ci                    mp->changes_map[y0 + x + mp->avctx->width * 3] < w) {
223cabdff1aSopenharmony_ci                    for (i = (x + 3) & ~3; i < x + w; i += 4) {
224cabdff1aSopenharmony_ci                        mp->hpt[((y / 4) * mp->avctx->width + i) / 4] = mp_get_yuv_from_rgb(mp, i, y);
225cabdff1aSopenharmony_ci                    }
226cabdff1aSopenharmony_ci                }
227cabdff1aSopenharmony_ci            }
228cabdff1aSopenharmony_ci            x += w;
229cabdff1aSopenharmony_ci            memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
230cabdff1aSopenharmony_ci            p = mp_get_yuv_from_rgb(mp, x - 1, y);
231cabdff1aSopenharmony_ci        } else {
232cabdff1aSopenharmony_ci            p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb));
233cabdff1aSopenharmony_ci            p.y = av_clip_uintp2(p.y, 5);
234cabdff1aSopenharmony_ci            if ((x & 3) == 0) {
235cabdff1aSopenharmony_ci                if ((y & 3) == 0) {
236cabdff1aSopenharmony_ci                    p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb));
237cabdff1aSopenharmony_ci                    p.v = av_clip_intp2(p.v, 5);
238cabdff1aSopenharmony_ci                    p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb));
239cabdff1aSopenharmony_ci                    p.u = av_clip_intp2(p.u, 5);
240cabdff1aSopenharmony_ci                    mp->hpt[((y / 4) * mp->avctx->width + x) / 4] = p;
241cabdff1aSopenharmony_ci                } else {
242cabdff1aSopenharmony_ci                    p.v = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].v;
243cabdff1aSopenharmony_ci                    p.u = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].u;
244cabdff1aSopenharmony_ci                }
245cabdff1aSopenharmony_ci            }
246cabdff1aSopenharmony_ci            mp_set_rgb_from_yuv(mp, x, y, &p);
247cabdff1aSopenharmony_ci            ++x;
248cabdff1aSopenharmony_ci        }
249cabdff1aSopenharmony_ci    }
250cabdff1aSopenharmony_ci}
251cabdff1aSopenharmony_ci
252cabdff1aSopenharmony_cistatic void mp_decode_frame_helper(MotionPixelsContext *mp, GetBitContext *gb)
253cabdff1aSopenharmony_ci{
254cabdff1aSopenharmony_ci    YuvPixel p;
255cabdff1aSopenharmony_ci    int y, y0;
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ci    av_assert1(mp->changes_map[0]);
258cabdff1aSopenharmony_ci
259cabdff1aSopenharmony_ci    for (y = 0; y < mp->avctx->height; ++y) {
260cabdff1aSopenharmony_ci        if (mp->changes_map[y * mp->avctx->width] != 0) {
261cabdff1aSopenharmony_ci            memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
262cabdff1aSopenharmony_ci            p = mp_get_yuv_from_rgb(mp, 0, y);
263cabdff1aSopenharmony_ci        } else {
264cabdff1aSopenharmony_ci            p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb));
265cabdff1aSopenharmony_ci            p.y = av_clip_uintp2(p.y, 5);
266cabdff1aSopenharmony_ci            if ((y & 3) == 0) {
267cabdff1aSopenharmony_ci                p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb));
268cabdff1aSopenharmony_ci                p.v = av_clip_intp2(p.v, 5);
269cabdff1aSopenharmony_ci                p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb));
270cabdff1aSopenharmony_ci                p.u = av_clip_intp2(p.u, 5);
271cabdff1aSopenharmony_ci            }
272cabdff1aSopenharmony_ci            mp->vpt[y] = p;
273cabdff1aSopenharmony_ci            mp_set_rgb_from_yuv(mp, 0, y, &p);
274cabdff1aSopenharmony_ci        }
275cabdff1aSopenharmony_ci    }
276cabdff1aSopenharmony_ci    for (y0 = 0; y0 < 2; ++y0)
277cabdff1aSopenharmony_ci        for (y = y0; y < mp->avctx->height; y += 2)
278cabdff1aSopenharmony_ci            mp_decode_line(mp, gb, y);
279cabdff1aSopenharmony_ci}
280cabdff1aSopenharmony_ci
281cabdff1aSopenharmony_cistatic int mp_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
282cabdff1aSopenharmony_ci                           int *got_frame, AVPacket *avpkt)
283cabdff1aSopenharmony_ci{
284cabdff1aSopenharmony_ci    const uint8_t *buf = avpkt->data;
285cabdff1aSopenharmony_ci    int buf_size = avpkt->size;
286cabdff1aSopenharmony_ci    MotionPixelsContext *mp = avctx->priv_data;
287cabdff1aSopenharmony_ci    GetBitContext gb;
288cabdff1aSopenharmony_ci    int i, count1, count2, sz, ret;
289cabdff1aSopenharmony_ci
290cabdff1aSopenharmony_ci    if ((ret = ff_reget_buffer(avctx, mp->frame, 0)) < 0)
291cabdff1aSopenharmony_ci        return ret;
292cabdff1aSopenharmony_ci
293cabdff1aSopenharmony_ci    /* le32 bitstream msb first */
294cabdff1aSopenharmony_ci    av_fast_padded_malloc(&mp->bswapbuf, &mp->bswapbuf_size, buf_size);
295cabdff1aSopenharmony_ci    if (!mp->bswapbuf)
296cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
297cabdff1aSopenharmony_ci    mp->bdsp.bswap_buf((uint32_t *) mp->bswapbuf, (const uint32_t *) buf,
298cabdff1aSopenharmony_ci                       buf_size / 4);
299cabdff1aSopenharmony_ci    if (buf_size & 3)
300cabdff1aSopenharmony_ci        memcpy(mp->bswapbuf + (buf_size & ~3), buf + (buf_size & ~3), buf_size & 3);
301cabdff1aSopenharmony_ci    init_get_bits(&gb, mp->bswapbuf, buf_size * 8);
302cabdff1aSopenharmony_ci
303cabdff1aSopenharmony_ci    memset(mp->changes_map, 0, avctx->width * avctx->height);
304cabdff1aSopenharmony_ci    for (i = !(avctx->extradata[1] & 2); i < 2; ++i) {
305cabdff1aSopenharmony_ci        count1 = get_bits(&gb, 12);
306cabdff1aSopenharmony_ci        count2 = get_bits(&gb, 12);
307cabdff1aSopenharmony_ci        mp_read_changes_map(mp, &gb, count1, 8, i);
308cabdff1aSopenharmony_ci        mp_read_changes_map(mp, &gb, count2, 4, i);
309cabdff1aSopenharmony_ci    }
310cabdff1aSopenharmony_ci
311cabdff1aSopenharmony_ci    mp->codes_count = get_bits(&gb, 4);
312cabdff1aSopenharmony_ci    if (mp->codes_count == 0)
313cabdff1aSopenharmony_ci        goto end;
314cabdff1aSopenharmony_ci
315cabdff1aSopenharmony_ci    if (mp->changes_map[0] == 0) {
316cabdff1aSopenharmony_ci        *(uint16_t *)mp->frame->data[0] = get_bits(&gb, 15);
317cabdff1aSopenharmony_ci        mp->changes_map[0] = 1;
318cabdff1aSopenharmony_ci    }
319cabdff1aSopenharmony_ci    if (mp_read_codes_table(mp, &gb) < 0)
320cabdff1aSopenharmony_ci        goto end;
321cabdff1aSopenharmony_ci
322cabdff1aSopenharmony_ci    sz = get_bits(&gb, 18);
323cabdff1aSopenharmony_ci    if (avctx->extradata[0] != 5)
324cabdff1aSopenharmony_ci        sz += get_bits(&gb, 18);
325cabdff1aSopenharmony_ci    if (sz == 0)
326cabdff1aSopenharmony_ci        goto end;
327cabdff1aSopenharmony_ci
328cabdff1aSopenharmony_ci    if (mp->codes_count > 1) {
329cabdff1aSopenharmony_ci        /* The entries of the mp->codes array are sorted from right to left
330cabdff1aSopenharmony_ci         * in the Huffman tree, hence -(int)sizeof(HuffCode). */
331cabdff1aSopenharmony_ci        ret = ff_init_vlc_from_lengths(&mp->vlc, mp->max_codes_bits, mp->codes_count,
332cabdff1aSopenharmony_ci                                       &mp->codes[mp->codes_count - 1].size,  -(int)sizeof(HuffCode),
333cabdff1aSopenharmony_ci                                       &mp->codes[mp->codes_count - 1].delta, -(int)sizeof(HuffCode), 1,
334cabdff1aSopenharmony_ci                                       0, 0, avctx);
335cabdff1aSopenharmony_ci        if (ret < 0)
336cabdff1aSopenharmony_ci            goto end;
337cabdff1aSopenharmony_ci    }
338cabdff1aSopenharmony_ci    mp_decode_frame_helper(mp, &gb);
339cabdff1aSopenharmony_ci    ff_free_vlc(&mp->vlc);
340cabdff1aSopenharmony_ci
341cabdff1aSopenharmony_ciend:
342cabdff1aSopenharmony_ci    if ((ret = av_frame_ref(rframe, mp->frame)) < 0)
343cabdff1aSopenharmony_ci        return ret;
344cabdff1aSopenharmony_ci    *got_frame       = 1;
345cabdff1aSopenharmony_ci    return buf_size;
346cabdff1aSopenharmony_ci}
347cabdff1aSopenharmony_ci
348cabdff1aSopenharmony_ciconst FFCodec ff_motionpixels_decoder = {
349cabdff1aSopenharmony_ci    .p.name         = "motionpixels",
350cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Motion Pixels video"),
351cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
352cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_MOTIONPIXELS,
353cabdff1aSopenharmony_ci    .priv_data_size = sizeof(MotionPixelsContext),
354cabdff1aSopenharmony_ci    .init           = mp_decode_init,
355cabdff1aSopenharmony_ci    .close          = mp_decode_end,
356cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(mp_decode_frame),
357cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1,
358cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_INIT_THREADSAFE,
359cabdff1aSopenharmony_ci};
360