1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * MobiClip Video decoder
3cabdff1aSopenharmony_ci * Copyright (c) 2015-2016 Florian Nouwt
4cabdff1aSopenharmony_ci * Copyright (c) 2017 Adib Surani
5cabdff1aSopenharmony_ci * Copyright (c) 2020 Paul B Mahol
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * This file is part of FFmpeg.
8cabdff1aSopenharmony_ci *
9cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
10cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
11cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
12cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
13cabdff1aSopenharmony_ci *
14cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
15cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
16cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17cabdff1aSopenharmony_ci * Lesser General Public License for more details.
18cabdff1aSopenharmony_ci *
19cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
20cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
21cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22cabdff1aSopenharmony_ci */
23cabdff1aSopenharmony_ci
24cabdff1aSopenharmony_ci#include <inttypes.h>
25cabdff1aSopenharmony_ci
26cabdff1aSopenharmony_ci#include "libavutil/avassert.h"
27cabdff1aSopenharmony_ci#include "libavutil/thread.h"
28cabdff1aSopenharmony_ci
29cabdff1aSopenharmony_ci#include "avcodec.h"
30cabdff1aSopenharmony_ci#include "bytestream.h"
31cabdff1aSopenharmony_ci#include "bswapdsp.h"
32cabdff1aSopenharmony_ci#include "codec_internal.h"
33cabdff1aSopenharmony_ci#include "get_bits.h"
34cabdff1aSopenharmony_ci#include "golomb.h"
35cabdff1aSopenharmony_ci#include "internal.h"
36cabdff1aSopenharmony_ci
37cabdff1aSopenharmony_ci#define MOBI_RL_VLC_BITS 12
38cabdff1aSopenharmony_ci#define MOBI_MV_VLC_BITS 6
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_cistatic const uint8_t zigzag4x4_tab[] =
41cabdff1aSopenharmony_ci{
42cabdff1aSopenharmony_ci    0x00, 0x04, 0x01, 0x02, 0x05, 0x08, 0x0C, 0x09, 0x06, 0x03, 0x07, 0x0A,
43cabdff1aSopenharmony_ci    0x0D, 0x0E, 0x0B, 0x0F
44cabdff1aSopenharmony_ci};
45cabdff1aSopenharmony_ci
46cabdff1aSopenharmony_cistatic const uint8_t quant4x4_tab[][16] =
47cabdff1aSopenharmony_ci{
48cabdff1aSopenharmony_ci    { 10, 13, 13, 10, 16, 10, 13, 13, 13, 13, 16, 10, 16, 13, 13, 16 },
49cabdff1aSopenharmony_ci    { 11, 14, 14, 11, 18, 11, 14, 14, 14, 14, 18, 11, 18, 14, 14, 18 },
50cabdff1aSopenharmony_ci    { 13, 16, 16, 13, 20, 13, 16, 16, 16, 16, 20, 13, 20, 16, 16, 20 },
51cabdff1aSopenharmony_ci    { 14, 18, 18, 14, 23, 14, 18, 18, 18, 18, 23, 14, 23, 18, 18, 23 },
52cabdff1aSopenharmony_ci    { 16, 20, 20, 16, 25, 16, 20, 20, 20, 20, 25, 16, 25, 20, 20, 25 },
53cabdff1aSopenharmony_ci    { 18, 23, 23, 18, 29, 18, 23, 23, 23, 23, 29, 18, 29, 23, 23, 29 },
54cabdff1aSopenharmony_ci};
55cabdff1aSopenharmony_ci
56cabdff1aSopenharmony_cistatic const uint8_t quant8x8_tab[][64] =
57cabdff1aSopenharmony_ci{
58cabdff1aSopenharmony_ci    { 20, 19, 19, 25, 18, 25, 19, 24, 24, 19, 20, 18, 32, 18, 20, 19, 19, 24, 24, 19, 19, 25, 18, 25, 18, 25, 18, 25, 19, 24, 24, 19,
59cabdff1aSopenharmony_ci      19, 24, 24, 19, 18, 32, 18, 20, 18, 32, 18, 24, 24, 19, 19, 24, 24, 18, 25, 18, 25, 18, 19, 24, 24, 19, 18, 32, 18, 24, 24, 18,},
60cabdff1aSopenharmony_ci    { 22, 21, 21, 28, 19, 28, 21, 26, 26, 21, 22, 19, 35, 19, 22, 21, 21, 26, 26, 21, 21, 28, 19, 28, 19, 28, 19, 28, 21, 26, 26, 21,
61cabdff1aSopenharmony_ci      21, 26, 26, 21, 19, 35, 19, 22, 19, 35, 19, 26, 26, 21, 21, 26, 26, 19, 28, 19, 28, 19, 21, 26, 26, 21, 19, 35, 19, 26, 26, 19,},
62cabdff1aSopenharmony_ci    { 26, 24, 24, 33, 23, 33, 24, 31, 31, 24, 26, 23, 42, 23, 26, 24, 24, 31, 31, 24, 24, 33, 23, 33, 23, 33, 23, 33, 24, 31, 31, 24,
63cabdff1aSopenharmony_ci      24, 31, 31, 24, 23, 42, 23, 26, 23, 42, 23, 31, 31, 24, 24, 31, 31, 23, 33, 23, 33, 23, 24, 31, 31, 24, 23, 42, 23, 31, 31, 23,},
64cabdff1aSopenharmony_ci    { 28, 26, 26, 35, 25, 35, 26, 33, 33, 26, 28, 25, 45, 25, 28, 26, 26, 33, 33, 26, 26, 35, 25, 35, 25, 35, 25, 35, 26, 33, 33, 26,
65cabdff1aSopenharmony_ci      26, 33, 33, 26, 25, 45, 25, 28, 25, 45, 25, 33, 33, 26, 26, 33, 33, 25, 35, 25, 35, 25, 26, 33, 33, 26, 25, 45, 25, 33, 33, 25,},
66cabdff1aSopenharmony_ci    { 32, 30, 30, 40, 28, 40, 30, 38, 38, 30, 32, 28, 51, 28, 32, 30, 30, 38, 38, 30, 30, 40, 28, 40, 28, 40, 28, 40, 30, 38, 38, 30,
67cabdff1aSopenharmony_ci      30, 38, 38, 30, 28, 51, 28, 32, 28, 51, 28, 38, 38, 30, 30, 38, 38, 28, 40, 28, 40, 28, 30, 38, 38, 30, 28, 51, 28, 38, 38, 28,},
68cabdff1aSopenharmony_ci    { 36, 34, 34, 46, 32, 46, 34, 43, 43, 34, 36, 32, 58, 32, 36, 34, 34, 43, 43, 34, 34, 46, 32, 46, 32, 46, 32, 46, 34, 43, 43, 34,
69cabdff1aSopenharmony_ci      34, 43, 43, 34, 32, 58, 32, 36, 32, 58, 32, 43, 43, 34, 34, 43, 43, 32, 46, 32, 46, 32, 34, 43, 43, 34, 32, 58, 32, 43, 43, 32,},
70cabdff1aSopenharmony_ci};
71cabdff1aSopenharmony_ci
72cabdff1aSopenharmony_cistatic const uint8_t block4x4_coefficients_tab[] =
73cabdff1aSopenharmony_ci{
74cabdff1aSopenharmony_ci    15, 0, 2, 1, 4, 8, 12, 3, 11, 13, 14, 7, 10, 5, 9, 6,
75cabdff1aSopenharmony_ci};
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_cistatic const uint8_t pframe_block4x4_coefficients_tab[] =
78cabdff1aSopenharmony_ci{
79cabdff1aSopenharmony_ci    0, 4, 1, 8, 2, 12, 3, 5, 10, 15, 7, 13, 14, 11, 9, 6,
80cabdff1aSopenharmony_ci};
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_cistatic const uint8_t block8x8_coefficients_tab[] =
83cabdff1aSopenharmony_ci{
84cabdff1aSopenharmony_ci    0x00, 0x1F, 0x3F, 0x0F, 0x08, 0x04, 0x02, 0x01, 0x0B, 0x0E, 0x1B, 0x0D,
85cabdff1aSopenharmony_ci    0x03, 0x07, 0x0C, 0x17, 0x1D, 0x0A, 0x1E, 0x05, 0x10, 0x2F, 0x37, 0x3B,
86cabdff1aSopenharmony_ci    0x13, 0x3D, 0x3E, 0x09, 0x1C, 0x06, 0x15, 0x1A, 0x33, 0x11, 0x12, 0x14,
87cabdff1aSopenharmony_ci    0x18, 0x20, 0x3C, 0x35, 0x19, 0x16, 0x3A, 0x30, 0x31, 0x32, 0x27, 0x34,
88cabdff1aSopenharmony_ci    0x2B, 0x2D, 0x39, 0x38, 0x23, 0x36, 0x2E, 0x21, 0x25, 0x22, 0x24, 0x2C,
89cabdff1aSopenharmony_ci    0x2A, 0x28, 0x29, 0x26,
90cabdff1aSopenharmony_ci};
91cabdff1aSopenharmony_ci
92cabdff1aSopenharmony_cistatic const uint8_t pframe_block8x8_coefficients_tab[] =
93cabdff1aSopenharmony_ci{
94cabdff1aSopenharmony_ci    0x00, 0x0F, 0x04, 0x01, 0x08, 0x02, 0x0C, 0x03, 0x05, 0x0A, 0x0D, 0x07, 0x0E, 0x0B, 0x1F, 0x09,
95cabdff1aSopenharmony_ci    0x06, 0x10, 0x3F, 0x1E, 0x17, 0x1D, 0x1B, 0x1C, 0x13, 0x18, 0x1A, 0x12, 0x11, 0x14, 0x15, 0x20,
96cabdff1aSopenharmony_ci    0x2F, 0x16, 0x19, 0x37, 0x3D, 0x3E, 0x3B, 0x3C, 0x33, 0x35, 0x21, 0x24, 0x22, 0x28, 0x23, 0x2C,
97cabdff1aSopenharmony_ci    0x30, 0x27, 0x2D, 0x25, 0x3A, 0x2B, 0x2E, 0x2A, 0x31, 0x34, 0x38, 0x32, 0x29, 0x26, 0x39, 0x36
98cabdff1aSopenharmony_ci};
99cabdff1aSopenharmony_ci
100cabdff1aSopenharmony_cistatic const uint8_t run_residue[2][256] =
101cabdff1aSopenharmony_ci{
102cabdff1aSopenharmony_ci    {
103cabdff1aSopenharmony_ci       12,  6,  4,  3,  3,  3,  3,  2,  2,  2,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,
104cabdff1aSopenharmony_ci        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
105cabdff1aSopenharmony_ci        3,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
106cabdff1aSopenharmony_ci        1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
107cabdff1aSopenharmony_ci        1, 27, 11,  7,  3,  2,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
108cabdff1aSopenharmony_ci        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
109cabdff1aSopenharmony_ci        1, 41,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
110cabdff1aSopenharmony_ci        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
111cabdff1aSopenharmony_ci    },
112cabdff1aSopenharmony_ci    {
113cabdff1aSopenharmony_ci       27, 10,  5,  4,  3,  3,  3,  3,  2,  2,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
114cabdff1aSopenharmony_ci        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
115cabdff1aSopenharmony_ci        8,  3,  2,  2,  2,  2,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
116cabdff1aSopenharmony_ci        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
117cabdff1aSopenharmony_ci        1, 15, 10,  8,  4,  3,  2,  2,  2,  2,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
118cabdff1aSopenharmony_ci        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
119cabdff1aSopenharmony_ci        1, 21,  7,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
120cabdff1aSopenharmony_ci        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
121cabdff1aSopenharmony_ci    },
122cabdff1aSopenharmony_ci};
123cabdff1aSopenharmony_ci
124cabdff1aSopenharmony_cistatic const uint8_t bits0[] = {
125cabdff1aSopenharmony_ci     9, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
126cabdff1aSopenharmony_ci    10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12,
127cabdff1aSopenharmony_ci    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  7, 10, 10,  9,
128cabdff1aSopenharmony_ci     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
129cabdff1aSopenharmony_ci     9,  9,  9,  9,  9,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
130cabdff1aSopenharmony_ci     8,  8,  8,  7,  7,  7,  7,  7,  7,  7,  7,  6,  6,  6,  6,
131cabdff1aSopenharmony_ci     6,  6,  6,  6,  6,  6,  5,  5,  5,  4,  2,  3,  4,  4,
132cabdff1aSopenharmony_ci};
133cabdff1aSopenharmony_ci
134cabdff1aSopenharmony_cistatic const uint16_t syms0[] = {
135cabdff1aSopenharmony_ci    0x0, 0x822, 0x803, 0xB, 0xA, 0xB81, 0xB61, 0xB41, 0xB21, 0x122,
136cabdff1aSopenharmony_ci    0x102, 0xE2, 0xC2, 0xA2, 0x63, 0x43, 0x24, 0xC, 0x25, 0x2E1, 0x301,
137cabdff1aSopenharmony_ci    0xBA1, 0xBC1, 0xBE1, 0xC01, 0x26, 0x44, 0x83, 0xA3, 0xC3, 0x142,
138cabdff1aSopenharmony_ci    0x321, 0x341, 0xC21, 0xC41, 0xC61, 0xC81, 0xCA1, 0xCC1, 0xCE1, 0xD01,
139cabdff1aSopenharmony_ci    0x0, 0x9, 0x8, 0xB01, 0xAE1, 0xAC1, 0xAA1, 0xA81, 0xA61, 0xA41, 0xA21,
140cabdff1aSopenharmony_ci    0x802, 0x2C1, 0x2A1, 0x281, 0x261, 0x241, 0x221, 0x201, 0x1E1, 0x82,
141cabdff1aSopenharmony_ci    0x62, 0x7, 0x6, 0xA01, 0x9E1, 0x9C1, 0x9A1, 0x981, 0x961, 0x941, 0x921,
142cabdff1aSopenharmony_ci    0x1C1, 0x1A1, 0x42, 0x23, 0x5, 0x901, 0x8E1, 0x8C1, 0x8A1, 0x181, 0x161,
143cabdff1aSopenharmony_ci    0x141, 0x4, 0x881, 0x861, 0x841, 0x821, 0x121, 0x101, 0xE1, 0xC1, 0x22,
144cabdff1aSopenharmony_ci    0x3, 0xA1, 0x81, 0x61, 0x801, 0x1, 0x21, 0x41, 0x2,
145cabdff1aSopenharmony_ci};
146cabdff1aSopenharmony_ci
147cabdff1aSopenharmony_cistatic const uint16_t syms1[] = {
148cabdff1aSopenharmony_ci    0x0, 0x807, 0x806, 0x16, 0x15, 0x842, 0x823, 0x805, 0x1A1, 0xA3, 0x102, 0x83,
149cabdff1aSopenharmony_ci    0x64, 0x44, 0x27, 0x14, 0x13, 0x17, 0x18, 0x28, 0x122, 0x862, 0x882, 0x9E1, 0xA01,
150cabdff1aSopenharmony_ci    0x19, 0x1A, 0x1B, 0x29, 0xC3, 0x2A, 0x45, 0xE3, 0x1C1, 0x808, 0x8A2, 0x8C2, 0xA21,
151cabdff1aSopenharmony_ci    0xA41, 0xA61, 0xA81, 0x0, 0x12, 0x11, 0x9C1, 0x9A1, 0x981, 0x961, 0x941, 0x822, 0x804,
152cabdff1aSopenharmony_ci    0x181, 0x161, 0xE2, 0xC2, 0xA2, 0x63, 0x43, 0x26, 0x25, 0x10, 0x82, 0xF, 0xE, 0xD, 0x901,
153cabdff1aSopenharmony_ci    0x8E1, 0x8C1, 0x803, 0x141, 0x121, 0x101, 0x921, 0x62, 0x24, 0xC, 0xB, 0xA, 0x881, 0x861,
154cabdff1aSopenharmony_ci    0xC1, 0x8A1, 0xE1, 0x42, 0x23, 0x9, 0x802, 0xA1, 0x841, 0x821, 0x81, 0x61, 0x8, 0x7, 0x22,
155cabdff1aSopenharmony_ci    0x6, 0x41, 0x5, 0x4, 0x801, 0x1, 0x2, 0x21, 0x3,
156cabdff1aSopenharmony_ci};
157cabdff1aSopenharmony_ci
158cabdff1aSopenharmony_cistatic const uint8_t mv_len[16] =
159cabdff1aSopenharmony_ci{
160cabdff1aSopenharmony_ci    10, 8, 8, 7, 8, 8, 8, 7, 8, 8, 8, 7, 7, 7, 7, 6,
161cabdff1aSopenharmony_ci};
162cabdff1aSopenharmony_ci
163cabdff1aSopenharmony_cistatic const uint8_t mv_bits[2][16][10] =
164cabdff1aSopenharmony_ci{
165cabdff1aSopenharmony_ci    {
166cabdff1aSopenharmony_ci        { 2, 3, 3, 5, 5, 4, 4, 5, 5, 2 },
167cabdff1aSopenharmony_ci        { 2, 3, 4, 4, 3, 4, 4, 2 },
168cabdff1aSopenharmony_ci        { 3, 4, 4, 2, 4, 4, 3, 2 },
169cabdff1aSopenharmony_ci        { 1, 3, 4, 5, 5, 3, 3 },
170cabdff1aSopenharmony_ci        { 2, 4, 4, 3, 3, 4, 4, 2 },
171cabdff1aSopenharmony_ci        { 2, 3, 4, 4, 4, 4, 3, 2 },
172cabdff1aSopenharmony_ci        { 2, 3, 4, 4, 4, 4, 3, 2 },
173cabdff1aSopenharmony_ci        { 2, 2, 3, 4, 5, 5, 2 },
174cabdff1aSopenharmony_ci        { 2, 3, 4, 4, 3, 4, 4, 2 },
175cabdff1aSopenharmony_ci        { 2, 4, 4, 3, 4, 4, 3, 2 },
176cabdff1aSopenharmony_ci        { 2, 3, 3, 5, 5, 4, 3, 2 },
177cabdff1aSopenharmony_ci        { 2, 3, 4, 4, 3, 3, 2 },
178cabdff1aSopenharmony_ci        { 1, 4, 4, 3, 3, 4, 4 },
179cabdff1aSopenharmony_ci        { 2, 3, 4, 4, 3, 3, 2 },
180cabdff1aSopenharmony_ci        { 2, 3, 4, 4, 3, 3, 2 },
181cabdff1aSopenharmony_ci        { 3, 3, 2, 2, 3, 3 },
182cabdff1aSopenharmony_ci    },
183cabdff1aSopenharmony_ci    {
184cabdff1aSopenharmony_ci        { 3, 4, 5, 5, 3, 5, 6, 6, 4, 1 },
185cabdff1aSopenharmony_ci        { 2, 3, 4, 5, 5, 2, 3, 3 },
186cabdff1aSopenharmony_ci        { 2, 4, 4, 3, 3, 4, 4, 2 },
187cabdff1aSopenharmony_ci        { 1, 4, 4, 3, 4, 4, 3 },
188cabdff1aSopenharmony_ci        { 3, 3, 2, 4, 5, 5, 3, 2 },
189cabdff1aSopenharmony_ci        { 3, 4, 4, 3, 3, 3, 3, 2 },
190cabdff1aSopenharmony_ci        { 1, 3, 3, 4, 4, 4, 5, 5 },
191cabdff1aSopenharmony_ci        { 1, 4, 4, 3, 3, 4, 4 },
192cabdff1aSopenharmony_ci        { 2, 4, 4, 3, 3, 4, 4, 2 },
193cabdff1aSopenharmony_ci        { 1, 3, 3, 4, 4, 4, 5, 5 },
194cabdff1aSopenharmony_ci        { 2, 3, 4, 4, 4, 4, 3, 2 },
195cabdff1aSopenharmony_ci        { 2, 3, 3, 4, 4, 3, 2 },
196cabdff1aSopenharmony_ci        { 1, 4, 4, 3, 3, 4, 4 },
197cabdff1aSopenharmony_ci        { 1, 4, 4, 3, 3, 4, 4 },
198cabdff1aSopenharmony_ci        { 2, 3, 3, 4, 4, 3, 2 },
199cabdff1aSopenharmony_ci        { 2, 3, 3, 3, 3, 2 },
200cabdff1aSopenharmony_ci    }
201cabdff1aSopenharmony_ci};
202cabdff1aSopenharmony_ci
203cabdff1aSopenharmony_cistatic const uint8_t mv_syms[2][16][10] =
204cabdff1aSopenharmony_ci{
205cabdff1aSopenharmony_ci    {
206cabdff1aSopenharmony_ci        { 1, 8, 9, 4, 3, 2, 7, 5, 6, 0 },
207cabdff1aSopenharmony_ci        { 0, 9, 5, 4, 2, 3, 8, 1 },
208cabdff1aSopenharmony_ci        { 3, 9, 5, 0, 4, 8, 2, 1 },
209cabdff1aSopenharmony_ci        { 1, 3, 4, 8, 5, 2, 0 },
210cabdff1aSopenharmony_ci        { 0, 5, 4, 8, 2, 3, 9, 1 },
211cabdff1aSopenharmony_ci        { 0, 3, 5, 9, 4, 8, 2, 1 },
212cabdff1aSopenharmony_ci        { 0, 3, 9, 5, 8, 4, 2, 1 },
213cabdff1aSopenharmony_ci        { 0, 2, 3, 4, 8, 5, 1 },
214cabdff1aSopenharmony_ci        { 0, 3, 8, 4, 2, 5, 9, 1 },
215cabdff1aSopenharmony_ci        { 2, 8, 9, 3, 5, 4, 0, 1 },
216cabdff1aSopenharmony_ci        { 0, 4, 3, 8, 9, 5, 2, 1 },
217cabdff1aSopenharmony_ci        { 0, 4, 8, 5, 3, 2, 1 },
218cabdff1aSopenharmony_ci        { 1, 9, 4, 2, 0, 5, 3 },
219cabdff1aSopenharmony_ci        { 2, 4, 9, 5, 3, 0, 1 },
220cabdff1aSopenharmony_ci        { 0, 4, 9, 5, 3, 2, 1 },
221cabdff1aSopenharmony_ci        { 5, 4, 1, 0, 3, 2 },
222cabdff1aSopenharmony_ci    },
223cabdff1aSopenharmony_ci    {
224cabdff1aSopenharmony_ci        { 8, 2, 3, 6, 1, 7, 5, 4, 9, 0 },
225cabdff1aSopenharmony_ci        { 9, 2, 3, 5, 4, 1, 8, 0 },
226cabdff1aSopenharmony_ci        { 0, 5, 4, 2, 9, 3, 8, 1 },
227cabdff1aSopenharmony_ci        { 1, 5, 4, 2, 8, 3, 0 },
228cabdff1aSopenharmony_ci        { 2, 9, 8, 3, 5, 4, 0, 1 },
229cabdff1aSopenharmony_ci        { 3, 5, 4, 2, 9, 8, 0, 1 },
230cabdff1aSopenharmony_ci        { 1, 2, 0, 9, 8, 3, 5, 4 },
231cabdff1aSopenharmony_ci        { 1, 8, 5, 2, 0, 4, 3 },
232cabdff1aSopenharmony_ci        { 0, 5, 4, 2, 8, 3, 9, 1 },
233cabdff1aSopenharmony_ci        { 1, 2, 0, 9, 8, 3, 5, 4 },
234cabdff1aSopenharmony_ci        { 0, 3, 9, 8, 5, 4, 2, 1 },
235cabdff1aSopenharmony_ci        { 0, 4, 3, 8, 5, 2, 1 },
236cabdff1aSopenharmony_ci        { 1, 5, 4, 2, 0, 9, 3 },
237cabdff1aSopenharmony_ci        { 1, 9, 5, 2, 0, 4, 3 },
238cabdff1aSopenharmony_ci        { 0, 5, 3, 9, 4, 2, 1 },
239cabdff1aSopenharmony_ci        { 0, 4, 5, 3, 2, 1 },
240cabdff1aSopenharmony_ci    }
241cabdff1aSopenharmony_ci};
242cabdff1aSopenharmony_ci
243cabdff1aSopenharmony_citypedef struct BlockXY {
244cabdff1aSopenharmony_ci    int w, h;
245cabdff1aSopenharmony_ci    int ax, ay;
246cabdff1aSopenharmony_ci    int x, y;
247cabdff1aSopenharmony_ci    int size;
248cabdff1aSopenharmony_ci    uint8_t *block;
249cabdff1aSopenharmony_ci    int linesize;
250cabdff1aSopenharmony_ci} BlockXY;
251cabdff1aSopenharmony_ci
252cabdff1aSopenharmony_citypedef struct MotionXY {
253cabdff1aSopenharmony_ci    int x, y;
254cabdff1aSopenharmony_ci} MotionXY;
255cabdff1aSopenharmony_ci
256cabdff1aSopenharmony_citypedef struct MobiClipContext {
257cabdff1aSopenharmony_ci    AVFrame *pic[6];
258cabdff1aSopenharmony_ci
259cabdff1aSopenharmony_ci    int current_pic;
260cabdff1aSopenharmony_ci    int moflex;
261cabdff1aSopenharmony_ci    int dct_tab_idx;
262cabdff1aSopenharmony_ci    int quantizer;
263cabdff1aSopenharmony_ci
264cabdff1aSopenharmony_ci    GetBitContext gb;
265cabdff1aSopenharmony_ci
266cabdff1aSopenharmony_ci    uint8_t *bitstream;
267cabdff1aSopenharmony_ci    int bitstream_size;
268cabdff1aSopenharmony_ci
269cabdff1aSopenharmony_ci    int     qtab[2][64];
270cabdff1aSopenharmony_ci    uint8_t pre[32];
271cabdff1aSopenharmony_ci    MotionXY *motion;
272cabdff1aSopenharmony_ci    int     motion_size;
273cabdff1aSopenharmony_ci
274cabdff1aSopenharmony_ci    BswapDSPContext bdsp;
275cabdff1aSopenharmony_ci} MobiClipContext;
276cabdff1aSopenharmony_ci
277cabdff1aSopenharmony_cistatic VLC rl_vlc[2];
278cabdff1aSopenharmony_cistatic VLC mv_vlc[2][16];
279cabdff1aSopenharmony_ci
280cabdff1aSopenharmony_cistatic av_cold void mobiclip_init_static(void)
281cabdff1aSopenharmony_ci{
282cabdff1aSopenharmony_ci    INIT_VLC_STATIC_FROM_LENGTHS(&rl_vlc[0], MOBI_RL_VLC_BITS, 104,
283cabdff1aSopenharmony_ci                                 bits0, sizeof(*bits0),
284cabdff1aSopenharmony_ci                                 syms0, sizeof(*syms0), sizeof(*syms0),
285cabdff1aSopenharmony_ci                                 0, 0, 1 << MOBI_RL_VLC_BITS);
286cabdff1aSopenharmony_ci    INIT_VLC_STATIC_FROM_LENGTHS(&rl_vlc[1], MOBI_RL_VLC_BITS, 104,
287cabdff1aSopenharmony_ci                                 bits0, sizeof(*bits0),
288cabdff1aSopenharmony_ci                                 syms1, sizeof(*syms1), sizeof(*syms1),
289cabdff1aSopenharmony_ci                                 0, 0, 1 << MOBI_RL_VLC_BITS);
290cabdff1aSopenharmony_ci    for (int i = 0; i < 2; i++) {
291cabdff1aSopenharmony_ci        static VLCElem vlc_buf[2 * 16 << MOBI_MV_VLC_BITS];
292cabdff1aSopenharmony_ci        for (int j = 0; j < 16; j++) {
293cabdff1aSopenharmony_ci            mv_vlc[i][j].table           = &vlc_buf[(16 * i + j) << MOBI_MV_VLC_BITS];
294cabdff1aSopenharmony_ci            mv_vlc[i][j].table_allocated = 1 << MOBI_MV_VLC_BITS;
295cabdff1aSopenharmony_ci            ff_init_vlc_from_lengths(&mv_vlc[i][j], MOBI_MV_VLC_BITS, mv_len[j],
296cabdff1aSopenharmony_ci                                     mv_bits[i][j], sizeof(*mv_bits[i][j]),
297cabdff1aSopenharmony_ci                                     mv_syms[i][j], sizeof(*mv_syms[i][j]), sizeof(*mv_syms[i][j]),
298cabdff1aSopenharmony_ci                                     0, INIT_VLC_USE_NEW_STATIC, NULL);
299cabdff1aSopenharmony_ci        }
300cabdff1aSopenharmony_ci    }
301cabdff1aSopenharmony_ci}
302cabdff1aSopenharmony_ci
303cabdff1aSopenharmony_cistatic av_cold int mobiclip_init(AVCodecContext *avctx)
304cabdff1aSopenharmony_ci{
305cabdff1aSopenharmony_ci    static AVOnce init_static_once = AV_ONCE_INIT;
306cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
307cabdff1aSopenharmony_ci
308cabdff1aSopenharmony_ci    if (avctx->width & 15 || avctx->height & 15) {
309cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "width/height not multiple of 16\n");
310cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
311cabdff1aSopenharmony_ci    }
312cabdff1aSopenharmony_ci
313cabdff1aSopenharmony_ci    ff_bswapdsp_init(&s->bdsp);
314cabdff1aSopenharmony_ci
315cabdff1aSopenharmony_ci    avctx->pix_fmt = AV_PIX_FMT_YUV420P;
316cabdff1aSopenharmony_ci
317cabdff1aSopenharmony_ci    s->motion = av_calloc(avctx->width / 16 + 3, sizeof(MotionXY));
318cabdff1aSopenharmony_ci    if (!s->motion)
319cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
320cabdff1aSopenharmony_ci    s->motion_size = (avctx->width / 16 + 3) * sizeof(MotionXY);
321cabdff1aSopenharmony_ci
322cabdff1aSopenharmony_ci    for (int i = 0; i < 6; i++) {
323cabdff1aSopenharmony_ci        s->pic[i] = av_frame_alloc();
324cabdff1aSopenharmony_ci        if (!s->pic[i])
325cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
326cabdff1aSopenharmony_ci    }
327cabdff1aSopenharmony_ci
328cabdff1aSopenharmony_ci    ff_thread_once(&init_static_once, mobiclip_init_static);
329cabdff1aSopenharmony_ci
330cabdff1aSopenharmony_ci    return 0;
331cabdff1aSopenharmony_ci}
332cabdff1aSopenharmony_ci
333cabdff1aSopenharmony_cistatic int setup_qtables(AVCodecContext *avctx, int64_t quantizer)
334cabdff1aSopenharmony_ci{
335cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
336cabdff1aSopenharmony_ci    int qx, qy;
337cabdff1aSopenharmony_ci
338cabdff1aSopenharmony_ci    if (quantizer < 12 || quantizer > 161)
339cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
340cabdff1aSopenharmony_ci
341cabdff1aSopenharmony_ci    s->quantizer = quantizer;
342cabdff1aSopenharmony_ci
343cabdff1aSopenharmony_ci    qx = quantizer % 6;
344cabdff1aSopenharmony_ci    qy = quantizer / 6;
345cabdff1aSopenharmony_ci
346cabdff1aSopenharmony_ci    for (int i = 0; i < 16; i++)
347cabdff1aSopenharmony_ci        s->qtab[0][i] = quant4x4_tab[qx][i] << qy;
348cabdff1aSopenharmony_ci
349cabdff1aSopenharmony_ci    for (int i = 0; i < 64; i++)
350cabdff1aSopenharmony_ci        s->qtab[1][i] = quant8x8_tab[qx][i] << (qy - 2);
351cabdff1aSopenharmony_ci
352cabdff1aSopenharmony_ci    for (int i = 0; i < 20; i++)
353cabdff1aSopenharmony_ci        s->pre[i] = 9;
354cabdff1aSopenharmony_ci
355cabdff1aSopenharmony_ci    return 0;
356cabdff1aSopenharmony_ci}
357cabdff1aSopenharmony_ci
358cabdff1aSopenharmony_cistatic void inverse4(unsigned *rs)
359cabdff1aSopenharmony_ci{
360cabdff1aSopenharmony_ci    unsigned a = rs[0] + rs[2];
361cabdff1aSopenharmony_ci    unsigned b = rs[0] - rs[2];
362cabdff1aSopenharmony_ci    unsigned c = rs[1] + ((int)rs[3] >> 1);
363cabdff1aSopenharmony_ci    unsigned d = ((int)rs[1] >> 1) - rs[3];
364cabdff1aSopenharmony_ci
365cabdff1aSopenharmony_ci    rs[0] = a + c;
366cabdff1aSopenharmony_ci    rs[1] = b + d;
367cabdff1aSopenharmony_ci    rs[2] = b - d;
368cabdff1aSopenharmony_ci    rs[3] = a - c;
369cabdff1aSopenharmony_ci}
370cabdff1aSopenharmony_ci
371cabdff1aSopenharmony_cistatic void idct(int *arr, int size)
372cabdff1aSopenharmony_ci{
373cabdff1aSopenharmony_ci    int e, f, g, h;
374cabdff1aSopenharmony_ci    unsigned x3, x2, x1, x0;
375cabdff1aSopenharmony_ci    int tmp[4];
376cabdff1aSopenharmony_ci
377cabdff1aSopenharmony_ci    if (size == 4) {
378cabdff1aSopenharmony_ci        inverse4(arr);
379cabdff1aSopenharmony_ci        return;
380cabdff1aSopenharmony_ci    }
381cabdff1aSopenharmony_ci
382cabdff1aSopenharmony_ci    tmp[0] = arr[0];
383cabdff1aSopenharmony_ci    tmp[1] = arr[2];
384cabdff1aSopenharmony_ci    tmp[2] = arr[4];
385cabdff1aSopenharmony_ci    tmp[3] = arr[6];
386cabdff1aSopenharmony_ci
387cabdff1aSopenharmony_ci    inverse4(tmp);
388cabdff1aSopenharmony_ci
389cabdff1aSopenharmony_ci    e = (unsigned)arr[7] + arr[1] - arr[3] - (arr[3] >> 1);
390cabdff1aSopenharmony_ci    f = (unsigned)arr[7] - arr[1] + arr[5] + (arr[5] >> 1);
391cabdff1aSopenharmony_ci    g = (unsigned)arr[5] - arr[3] - arr[7] - (arr[7] >> 1);
392cabdff1aSopenharmony_ci    h = (unsigned)arr[5] + arr[3] + arr[1] + (arr[1] >> 1);
393cabdff1aSopenharmony_ci    x3 = (unsigned)g + (h >> 2);
394cabdff1aSopenharmony_ci    x2 = (unsigned)e + (f >> 2);
395cabdff1aSopenharmony_ci    x1 = (e >> 2) - (unsigned)f;
396cabdff1aSopenharmony_ci    x0 = (unsigned)h - (g >> 2);
397cabdff1aSopenharmony_ci
398cabdff1aSopenharmony_ci    arr[0] = tmp[0] + x0;
399cabdff1aSopenharmony_ci    arr[1] = tmp[1] + x1;
400cabdff1aSopenharmony_ci    arr[2] = tmp[2] + x2;
401cabdff1aSopenharmony_ci    arr[3] = tmp[3] + x3;
402cabdff1aSopenharmony_ci    arr[4] = tmp[3] - x3;
403cabdff1aSopenharmony_ci    arr[5] = tmp[2] - x2;
404cabdff1aSopenharmony_ci    arr[6] = tmp[1] - x1;
405cabdff1aSopenharmony_ci    arr[7] = tmp[0] - x0;
406cabdff1aSopenharmony_ci}
407cabdff1aSopenharmony_ci
408cabdff1aSopenharmony_cistatic void read_run_encoding(AVCodecContext *avctx,
409cabdff1aSopenharmony_ci                              int *last, int *run, int *level)
410cabdff1aSopenharmony_ci{
411cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
412cabdff1aSopenharmony_ci    GetBitContext *gb = &s->gb;
413cabdff1aSopenharmony_ci    int n = get_vlc2(gb, rl_vlc[s->dct_tab_idx].table,
414cabdff1aSopenharmony_ci                     MOBI_RL_VLC_BITS, 1);
415cabdff1aSopenharmony_ci
416cabdff1aSopenharmony_ci    *last = (n >> 11) == 1;
417cabdff1aSopenharmony_ci    *run  = (n >> 5) & 0x3F;
418cabdff1aSopenharmony_ci    *level = n & 0x1F;
419cabdff1aSopenharmony_ci}
420cabdff1aSopenharmony_ci
421cabdff1aSopenharmony_cistatic int add_coefficients(AVCodecContext *avctx, AVFrame *frame,
422cabdff1aSopenharmony_ci                            int bx, int by, int size, int plane)
423cabdff1aSopenharmony_ci{
424cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
425cabdff1aSopenharmony_ci    GetBitContext *gb = &s->gb;
426cabdff1aSopenharmony_ci    int mat[64] = { 0 };
427cabdff1aSopenharmony_ci    const uint8_t *ztab = size == 8 ? ff_zigzag_direct : zigzag4x4_tab;
428cabdff1aSopenharmony_ci    const int *qtab = s->qtab[size == 8];
429cabdff1aSopenharmony_ci    uint8_t *dst = frame->data[plane] + by * frame->linesize[plane] + bx;
430cabdff1aSopenharmony_ci
431cabdff1aSopenharmony_ci    for (int pos = 0; get_bits_left(gb) > 0; pos++) {
432cabdff1aSopenharmony_ci        int qval, last, run, level;
433cabdff1aSopenharmony_ci
434cabdff1aSopenharmony_ci        read_run_encoding(avctx, &last, &run, &level);
435cabdff1aSopenharmony_ci
436cabdff1aSopenharmony_ci        if (level) {
437cabdff1aSopenharmony_ci            if (get_bits1(gb))
438cabdff1aSopenharmony_ci                level = -level;
439cabdff1aSopenharmony_ci        } else if (!get_bits1(gb)) {
440cabdff1aSopenharmony_ci            read_run_encoding(avctx, &last, &run, &level);
441cabdff1aSopenharmony_ci            level += run_residue[s->dct_tab_idx][(last ? 64 : 0) + run];
442cabdff1aSopenharmony_ci            if (get_bits1(gb))
443cabdff1aSopenharmony_ci                level = -level;
444cabdff1aSopenharmony_ci        } else if (!get_bits1(gb)) {
445cabdff1aSopenharmony_ci            read_run_encoding(avctx, &last, &run, &level);
446cabdff1aSopenharmony_ci            run += run_residue[s->dct_tab_idx][128 + (last ? 64 : 0) + level];
447cabdff1aSopenharmony_ci            if (get_bits1(gb))
448cabdff1aSopenharmony_ci                level = -level;
449cabdff1aSopenharmony_ci        } else {
450cabdff1aSopenharmony_ci            last  = get_bits1(gb);
451cabdff1aSopenharmony_ci            run   = get_bits(gb, 6);
452cabdff1aSopenharmony_ci            level = get_sbits(gb, 12);
453cabdff1aSopenharmony_ci        }
454cabdff1aSopenharmony_ci
455cabdff1aSopenharmony_ci        pos += run;
456cabdff1aSopenharmony_ci        if (pos >= size * size)
457cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
458cabdff1aSopenharmony_ci        qval = qtab[pos];
459cabdff1aSopenharmony_ci        mat[ztab[pos]] = qval *(unsigned)level;
460cabdff1aSopenharmony_ci
461cabdff1aSopenharmony_ci        if (last)
462cabdff1aSopenharmony_ci            break;
463cabdff1aSopenharmony_ci    }
464cabdff1aSopenharmony_ci
465cabdff1aSopenharmony_ci    mat[0] += 32;
466cabdff1aSopenharmony_ci    for (int y = 0; y < size; y++)
467cabdff1aSopenharmony_ci        idct(&mat[y * size], size);
468cabdff1aSopenharmony_ci
469cabdff1aSopenharmony_ci    for (int y = 0; y < size; y++) {
470cabdff1aSopenharmony_ci        for (int x = y + 1; x < size; x++) {
471cabdff1aSopenharmony_ci            int a = mat[x * size + y];
472cabdff1aSopenharmony_ci            int b = mat[y * size + x];
473cabdff1aSopenharmony_ci
474cabdff1aSopenharmony_ci            mat[y * size + x] = a;
475cabdff1aSopenharmony_ci            mat[x * size + y] = b;
476cabdff1aSopenharmony_ci        }
477cabdff1aSopenharmony_ci
478cabdff1aSopenharmony_ci        idct(&mat[y * size], size);
479cabdff1aSopenharmony_ci        for (int x = 0; x < size; x++)
480cabdff1aSopenharmony_ci            dst[x] = av_clip_uint8(dst[x] + (mat[y * size + x] >> 6));
481cabdff1aSopenharmony_ci        dst += frame->linesize[plane];
482cabdff1aSopenharmony_ci    }
483cabdff1aSopenharmony_ci
484cabdff1aSopenharmony_ci    return 0;
485cabdff1aSopenharmony_ci}
486cabdff1aSopenharmony_ci
487cabdff1aSopenharmony_cistatic int add_pframe_coefficients(AVCodecContext *avctx, AVFrame *frame,
488cabdff1aSopenharmony_ci                                   int bx, int by, int size, int plane)
489cabdff1aSopenharmony_ci{
490cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
491cabdff1aSopenharmony_ci    GetBitContext *gb = &s->gb;
492cabdff1aSopenharmony_ci    int ret, idx = get_ue_golomb_31(gb);
493cabdff1aSopenharmony_ci
494cabdff1aSopenharmony_ci    if (idx == 0) {
495cabdff1aSopenharmony_ci        return add_coefficients(avctx, frame, bx, by, size, plane);
496cabdff1aSopenharmony_ci    } else if ((unsigned)idx < FF_ARRAY_ELEMS(pframe_block4x4_coefficients_tab)) {
497cabdff1aSopenharmony_ci        int flags = pframe_block4x4_coefficients_tab[idx];
498cabdff1aSopenharmony_ci
499cabdff1aSopenharmony_ci        for (int y = by; y < by + 8; y += 4) {
500cabdff1aSopenharmony_ci            for (int x = bx; x < bx + 8; x += 4) {
501cabdff1aSopenharmony_ci                if (flags & 1) {
502cabdff1aSopenharmony_ci                    ret = add_coefficients(avctx, frame, x, y, 4, plane);
503cabdff1aSopenharmony_ci                    if (ret < 0)
504cabdff1aSopenharmony_ci                        return ret;
505cabdff1aSopenharmony_ci                }
506cabdff1aSopenharmony_ci                flags >>= 1;
507cabdff1aSopenharmony_ci            }
508cabdff1aSopenharmony_ci        }
509cabdff1aSopenharmony_ci        return 0;
510cabdff1aSopenharmony_ci    } else {
511cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
512cabdff1aSopenharmony_ci    }
513cabdff1aSopenharmony_ci}
514cabdff1aSopenharmony_ci
515cabdff1aSopenharmony_cistatic int adjust(int x, int size)
516cabdff1aSopenharmony_ci{
517cabdff1aSopenharmony_ci    return size == 16 ? (x + 1) >> 1 : x;
518cabdff1aSopenharmony_ci}
519cabdff1aSopenharmony_ci
520cabdff1aSopenharmony_cistatic uint8_t pget(BlockXY b)
521cabdff1aSopenharmony_ci{
522cabdff1aSopenharmony_ci    BlockXY ret = b;
523cabdff1aSopenharmony_ci    int x, y;
524cabdff1aSopenharmony_ci
525cabdff1aSopenharmony_ci    if (b.x == -1 && b.y >= b.size) {
526cabdff1aSopenharmony_ci        ret.x = -1, ret.y = b.size - 1;
527cabdff1aSopenharmony_ci    } else if (b.x >= -1 && b.y >= -1) {
528cabdff1aSopenharmony_ci        ret.x = b.x, ret.y = b.y;
529cabdff1aSopenharmony_ci    } else if (b.x == -1 && b.y == -2) {
530cabdff1aSopenharmony_ci        ret.x = 0, ret.y = -1;
531cabdff1aSopenharmony_ci    } else if (b.x == -2 && b.y == -1) {
532cabdff1aSopenharmony_ci        ret.x = -1, ret.y = 0;
533cabdff1aSopenharmony_ci    }
534cabdff1aSopenharmony_ci
535cabdff1aSopenharmony_ci    y = av_clip(ret.ay + ret.y, 0, ret.h - 1);
536cabdff1aSopenharmony_ci    x = av_clip(ret.ax + ret.x, 0, ret.w - 1);
537cabdff1aSopenharmony_ci
538cabdff1aSopenharmony_ci    return ret.block[y * ret.linesize + x];
539cabdff1aSopenharmony_ci}
540cabdff1aSopenharmony_ci
541cabdff1aSopenharmony_cistatic uint8_t half(int a, int b)
542cabdff1aSopenharmony_ci{
543cabdff1aSopenharmony_ci    return ((a + b) + 1) / 2;
544cabdff1aSopenharmony_ci}
545cabdff1aSopenharmony_ci
546cabdff1aSopenharmony_cistatic uint8_t half3(int a, int b, int c)
547cabdff1aSopenharmony_ci{
548cabdff1aSopenharmony_ci    return ((a + b + b + c) * 2 / 4 + 1) / 2;
549cabdff1aSopenharmony_ci}
550cabdff1aSopenharmony_ci
551cabdff1aSopenharmony_cistatic uint8_t pick_above(BlockXY bxy)
552cabdff1aSopenharmony_ci{
553cabdff1aSopenharmony_ci    bxy.y = bxy.y - 1;
554cabdff1aSopenharmony_ci
555cabdff1aSopenharmony_ci    return pget(bxy);
556cabdff1aSopenharmony_ci}
557cabdff1aSopenharmony_ci
558cabdff1aSopenharmony_cistatic uint8_t pick_left(BlockXY bxy)
559cabdff1aSopenharmony_ci{
560cabdff1aSopenharmony_ci    bxy.x = bxy.x - 1;
561cabdff1aSopenharmony_ci
562cabdff1aSopenharmony_ci    return pget(bxy);
563cabdff1aSopenharmony_ci}
564cabdff1aSopenharmony_ci
565cabdff1aSopenharmony_cistatic uint8_t half_horz(BlockXY bxy)
566cabdff1aSopenharmony_ci{
567cabdff1aSopenharmony_ci    BlockXY a = bxy, b = bxy, c = bxy;
568cabdff1aSopenharmony_ci
569cabdff1aSopenharmony_ci    a.x -= 1;
570cabdff1aSopenharmony_ci    c.x += 1;
571cabdff1aSopenharmony_ci
572cabdff1aSopenharmony_ci    return half3(pget(a), pget(b), pget(c));
573cabdff1aSopenharmony_ci}
574cabdff1aSopenharmony_ci
575cabdff1aSopenharmony_cistatic uint8_t half_vert(BlockXY bxy)
576cabdff1aSopenharmony_ci{
577cabdff1aSopenharmony_ci    BlockXY a = bxy, b = bxy, c = bxy;
578cabdff1aSopenharmony_ci
579cabdff1aSopenharmony_ci    a.y -= 1;
580cabdff1aSopenharmony_ci    c.y += 1;
581cabdff1aSopenharmony_ci
582cabdff1aSopenharmony_ci    return half3(pget(a), pget(b), pget(c));
583cabdff1aSopenharmony_ci}
584cabdff1aSopenharmony_ci
585cabdff1aSopenharmony_cistatic uint8_t pick_4(BlockXY bxy)
586cabdff1aSopenharmony_ci{
587cabdff1aSopenharmony_ci    int val;
588cabdff1aSopenharmony_ci
589cabdff1aSopenharmony_ci    if ((bxy.x % 2) == 0) {
590cabdff1aSopenharmony_ci        BlockXY ba, bb;
591cabdff1aSopenharmony_ci        int a, b;
592cabdff1aSopenharmony_ci
593cabdff1aSopenharmony_ci        ba = bxy;
594cabdff1aSopenharmony_ci        ba.x = -1;
595cabdff1aSopenharmony_ci        ba.y = bxy.y + bxy.x / 2;
596cabdff1aSopenharmony_ci        a = pget(ba);
597cabdff1aSopenharmony_ci
598cabdff1aSopenharmony_ci        bb = bxy;
599cabdff1aSopenharmony_ci        bb.x = -1;
600cabdff1aSopenharmony_ci        bb.y = bxy.y + bxy.x / 2 + 1;
601cabdff1aSopenharmony_ci        b = pget(bb);
602cabdff1aSopenharmony_ci
603cabdff1aSopenharmony_ci        val = half(a, b);
604cabdff1aSopenharmony_ci    } else {
605cabdff1aSopenharmony_ci        BlockXY ba;
606cabdff1aSopenharmony_ci
607cabdff1aSopenharmony_ci        ba = bxy;
608cabdff1aSopenharmony_ci        ba.x = -1;
609cabdff1aSopenharmony_ci        ba.y = bxy.y + bxy.x / 2 + 1;
610cabdff1aSopenharmony_ci        val = half_vert(ba);
611cabdff1aSopenharmony_ci    }
612cabdff1aSopenharmony_ci
613cabdff1aSopenharmony_ci    return val;
614cabdff1aSopenharmony_ci}
615cabdff1aSopenharmony_ci
616cabdff1aSopenharmony_cistatic uint8_t pick_5(BlockXY bxy)
617cabdff1aSopenharmony_ci{
618cabdff1aSopenharmony_ci    int val;
619cabdff1aSopenharmony_ci
620cabdff1aSopenharmony_ci    if (bxy.x == 0) {
621cabdff1aSopenharmony_ci        BlockXY a = bxy;
622cabdff1aSopenharmony_ci        BlockXY b = bxy;
623cabdff1aSopenharmony_ci
624cabdff1aSopenharmony_ci        a.x = -1;
625cabdff1aSopenharmony_ci        a.y -= 1;
626cabdff1aSopenharmony_ci
627cabdff1aSopenharmony_ci        b.x = -1;
628cabdff1aSopenharmony_ci
629cabdff1aSopenharmony_ci        val = half(pget(a), pget(b));
630cabdff1aSopenharmony_ci    } else if (bxy.y == 0) {
631cabdff1aSopenharmony_ci        BlockXY a = bxy;
632cabdff1aSopenharmony_ci
633cabdff1aSopenharmony_ci        a.x -= 2;
634cabdff1aSopenharmony_ci        a.y -= 1;
635cabdff1aSopenharmony_ci
636cabdff1aSopenharmony_ci        val = half_horz(a);
637cabdff1aSopenharmony_ci    } else if (bxy.x == 1) {
638cabdff1aSopenharmony_ci        BlockXY a = bxy;
639cabdff1aSopenharmony_ci
640cabdff1aSopenharmony_ci        a.x -= 2;
641cabdff1aSopenharmony_ci        a.y -= 1;
642cabdff1aSopenharmony_ci
643cabdff1aSopenharmony_ci        val = half_vert(a);
644cabdff1aSopenharmony_ci    } else {
645cabdff1aSopenharmony_ci        BlockXY a = bxy;
646cabdff1aSopenharmony_ci
647cabdff1aSopenharmony_ci        a.x -= 2;
648cabdff1aSopenharmony_ci        a.y -= 1;
649cabdff1aSopenharmony_ci
650cabdff1aSopenharmony_ci        val = pget(a);
651cabdff1aSopenharmony_ci    }
652cabdff1aSopenharmony_ci
653cabdff1aSopenharmony_ci    return val;
654cabdff1aSopenharmony_ci}
655cabdff1aSopenharmony_ci
656cabdff1aSopenharmony_cistatic uint8_t pick_6(BlockXY bxy)
657cabdff1aSopenharmony_ci{
658cabdff1aSopenharmony_ci    int val;
659cabdff1aSopenharmony_ci
660cabdff1aSopenharmony_ci    if (bxy.y == 0) {
661cabdff1aSopenharmony_ci        BlockXY a = bxy;
662cabdff1aSopenharmony_ci        BlockXY b = bxy;
663cabdff1aSopenharmony_ci
664cabdff1aSopenharmony_ci        a.x -= 1;
665cabdff1aSopenharmony_ci        a.y = -1;
666cabdff1aSopenharmony_ci
667cabdff1aSopenharmony_ci        b.y = -1;
668cabdff1aSopenharmony_ci
669cabdff1aSopenharmony_ci        val = half(pget(a), pget(b));
670cabdff1aSopenharmony_ci    } else if (bxy.x == 0) {
671cabdff1aSopenharmony_ci        BlockXY a = bxy;
672cabdff1aSopenharmony_ci
673cabdff1aSopenharmony_ci        a.x -= 1;
674cabdff1aSopenharmony_ci        a.y -= 2;
675cabdff1aSopenharmony_ci
676cabdff1aSopenharmony_ci        val = half_vert(a);
677cabdff1aSopenharmony_ci    } else if (bxy.y == 1) {
678cabdff1aSopenharmony_ci        BlockXY a = bxy;
679cabdff1aSopenharmony_ci
680cabdff1aSopenharmony_ci        a.x -= 1;
681cabdff1aSopenharmony_ci        a.y -= 2;
682cabdff1aSopenharmony_ci
683cabdff1aSopenharmony_ci        val = half_horz(a);
684cabdff1aSopenharmony_ci    } else {
685cabdff1aSopenharmony_ci        BlockXY a = bxy;
686cabdff1aSopenharmony_ci
687cabdff1aSopenharmony_ci        a.x -= 1;
688cabdff1aSopenharmony_ci        a.y -= 2;
689cabdff1aSopenharmony_ci
690cabdff1aSopenharmony_ci        val = pget(a);
691cabdff1aSopenharmony_ci    }
692cabdff1aSopenharmony_ci
693cabdff1aSopenharmony_ci    return val;
694cabdff1aSopenharmony_ci}
695cabdff1aSopenharmony_ci
696cabdff1aSopenharmony_cistatic uint8_t pick_7(BlockXY bxy)
697cabdff1aSopenharmony_ci{
698cabdff1aSopenharmony_ci    int clr, acc1, acc2;
699cabdff1aSopenharmony_ci    BlockXY a = bxy;
700cabdff1aSopenharmony_ci
701cabdff1aSopenharmony_ci    a.x -= 1;
702cabdff1aSopenharmony_ci    a.y -= 1;
703cabdff1aSopenharmony_ci    clr = pget(a);
704cabdff1aSopenharmony_ci    if (bxy.x && bxy.y)
705cabdff1aSopenharmony_ci        return clr;
706cabdff1aSopenharmony_ci
707cabdff1aSopenharmony_ci    if (bxy.x == 0) {
708cabdff1aSopenharmony_ci        a.x = -1;
709cabdff1aSopenharmony_ci        a.y = bxy.y;
710cabdff1aSopenharmony_ci    } else {
711cabdff1aSopenharmony_ci        a.x = bxy.x - 2;
712cabdff1aSopenharmony_ci        a.y = -1;
713cabdff1aSopenharmony_ci    }
714cabdff1aSopenharmony_ci    acc1 = pget(a);
715cabdff1aSopenharmony_ci
716cabdff1aSopenharmony_ci    if (bxy.y == 0) {
717cabdff1aSopenharmony_ci        a.x = bxy.x;
718cabdff1aSopenharmony_ci        a.y = -1;
719cabdff1aSopenharmony_ci    } else {
720cabdff1aSopenharmony_ci        a.x = -1;
721cabdff1aSopenharmony_ci        a.y = bxy.y - 2;
722cabdff1aSopenharmony_ci    }
723cabdff1aSopenharmony_ci    acc2 = pget(a);
724cabdff1aSopenharmony_ci
725cabdff1aSopenharmony_ci    return half3(acc1, clr, acc2);
726cabdff1aSopenharmony_ci}
727cabdff1aSopenharmony_ci
728cabdff1aSopenharmony_cistatic uint8_t pick_8(BlockXY bxy)
729cabdff1aSopenharmony_ci{
730cabdff1aSopenharmony_ci    BlockXY ba = bxy;
731cabdff1aSopenharmony_ci    BlockXY bb = bxy;
732cabdff1aSopenharmony_ci    int val;
733cabdff1aSopenharmony_ci
734cabdff1aSopenharmony_ci    if (bxy.y == 0) {
735cabdff1aSopenharmony_ci        int a, b;
736cabdff1aSopenharmony_ci
737cabdff1aSopenharmony_ci        ba.y = -1;
738cabdff1aSopenharmony_ci        a = pget(ba);
739cabdff1aSopenharmony_ci
740cabdff1aSopenharmony_ci        bb.x += 1;
741cabdff1aSopenharmony_ci        bb.y = -1;
742cabdff1aSopenharmony_ci
743cabdff1aSopenharmony_ci        b = pget(bb);
744cabdff1aSopenharmony_ci
745cabdff1aSopenharmony_ci        val = half(a, b);
746cabdff1aSopenharmony_ci    } else if (bxy.y == 1) {
747cabdff1aSopenharmony_ci        ba.x += 1;
748cabdff1aSopenharmony_ci        ba.y -= 2;
749cabdff1aSopenharmony_ci
750cabdff1aSopenharmony_ci        val = half_horz(ba);
751cabdff1aSopenharmony_ci    } else if (bxy.x < bxy.size - 1) {
752cabdff1aSopenharmony_ci        ba.x += 1;
753cabdff1aSopenharmony_ci        ba.y -= 2;
754cabdff1aSopenharmony_ci
755cabdff1aSopenharmony_ci        val = pget(ba);
756cabdff1aSopenharmony_ci    } else if (bxy.y % 2 == 0) {
757cabdff1aSopenharmony_ci        int a, b;
758cabdff1aSopenharmony_ci
759cabdff1aSopenharmony_ci        ba.x = bxy.y / 2 + bxy.size - 1;
760cabdff1aSopenharmony_ci        ba.y = -1;
761cabdff1aSopenharmony_ci        a = pget(ba);
762cabdff1aSopenharmony_ci
763cabdff1aSopenharmony_ci        bb.x = bxy.y / 2 + bxy.size;
764cabdff1aSopenharmony_ci        bb.y = -1;
765cabdff1aSopenharmony_ci
766cabdff1aSopenharmony_ci        b = pget(bb);
767cabdff1aSopenharmony_ci
768cabdff1aSopenharmony_ci        val = half(a, b);
769cabdff1aSopenharmony_ci    } else {
770cabdff1aSopenharmony_ci        ba.x = bxy.y / 2 + bxy.size;
771cabdff1aSopenharmony_ci        ba.y = -1;
772cabdff1aSopenharmony_ci
773cabdff1aSopenharmony_ci        val = half_horz(ba);
774cabdff1aSopenharmony_ci    }
775cabdff1aSopenharmony_ci
776cabdff1aSopenharmony_ci    return val;
777cabdff1aSopenharmony_ci}
778cabdff1aSopenharmony_ci
779cabdff1aSopenharmony_cistatic void block_fill_simple(uint8_t *block, int size, int linesize, int fill)
780cabdff1aSopenharmony_ci{
781cabdff1aSopenharmony_ci    for (int y = 0; y < size; y++) {
782cabdff1aSopenharmony_ci        memset(block, fill, size);
783cabdff1aSopenharmony_ci        block += linesize;
784cabdff1aSopenharmony_ci    }
785cabdff1aSopenharmony_ci}
786cabdff1aSopenharmony_ci
787cabdff1aSopenharmony_cistatic void block_fill(uint8_t *block, int size, int linesize,
788cabdff1aSopenharmony_ci                       int w, int h, int ax, int ay,
789cabdff1aSopenharmony_ci                       uint8_t (*pick)(BlockXY bxy))
790cabdff1aSopenharmony_ci{
791cabdff1aSopenharmony_ci    BlockXY bxy;
792cabdff1aSopenharmony_ci
793cabdff1aSopenharmony_ci    bxy.size = size;
794cabdff1aSopenharmony_ci    bxy.block = block;
795cabdff1aSopenharmony_ci    bxy.linesize = linesize;
796cabdff1aSopenharmony_ci    bxy.w = w;
797cabdff1aSopenharmony_ci    bxy.h = h;
798cabdff1aSopenharmony_ci    bxy.ay = ay;
799cabdff1aSopenharmony_ci    bxy.ax = ax;
800cabdff1aSopenharmony_ci
801cabdff1aSopenharmony_ci    for (int y = 0; y < size; y++) {
802cabdff1aSopenharmony_ci        bxy.y = y;
803cabdff1aSopenharmony_ci        for (int x = 0; x < size; x++) {
804cabdff1aSopenharmony_ci            uint8_t val;
805cabdff1aSopenharmony_ci
806cabdff1aSopenharmony_ci            bxy.x = x;
807cabdff1aSopenharmony_ci
808cabdff1aSopenharmony_ci            val = pick(bxy);
809cabdff1aSopenharmony_ci
810cabdff1aSopenharmony_ci            block[ax + x + (ay + y) * linesize] = val;
811cabdff1aSopenharmony_ci        }
812cabdff1aSopenharmony_ci    }
813cabdff1aSopenharmony_ci}
814cabdff1aSopenharmony_ci
815cabdff1aSopenharmony_cistatic int block_sum(const uint8_t *block, int w, int h, int linesize)
816cabdff1aSopenharmony_ci{
817cabdff1aSopenharmony_ci    int sum = 0;
818cabdff1aSopenharmony_ci
819cabdff1aSopenharmony_ci    for (int y = 0; y < h; y++) {
820cabdff1aSopenharmony_ci        for (int x = 0; x < w; x++) {
821cabdff1aSopenharmony_ci            sum += block[x];
822cabdff1aSopenharmony_ci        }
823cabdff1aSopenharmony_ci        block += linesize;
824cabdff1aSopenharmony_ci    }
825cabdff1aSopenharmony_ci
826cabdff1aSopenharmony_ci    return sum;
827cabdff1aSopenharmony_ci}
828cabdff1aSopenharmony_ci
829cabdff1aSopenharmony_cistatic int predict_intra(AVCodecContext *avctx, AVFrame *frame, int ax, int ay,
830cabdff1aSopenharmony_ci                          int pmode, int add_coeffs, int size, int plane)
831cabdff1aSopenharmony_ci{
832cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
833cabdff1aSopenharmony_ci    GetBitContext *gb = &s->gb;
834cabdff1aSopenharmony_ci    int w = avctx->width >> !!plane, h = avctx->height >> !!plane;
835cabdff1aSopenharmony_ci    int ret = 0;
836cabdff1aSopenharmony_ci
837cabdff1aSopenharmony_ci    switch (pmode) {
838cabdff1aSopenharmony_ci    case 0:
839cabdff1aSopenharmony_ci        block_fill(frame->data[plane], size, frame->linesize[plane], w, h, ax, ay, pick_above);
840cabdff1aSopenharmony_ci        break;
841cabdff1aSopenharmony_ci    case 1:
842cabdff1aSopenharmony_ci        block_fill(frame->data[plane], size, frame->linesize[plane], w, h, ax, ay, pick_left);
843cabdff1aSopenharmony_ci        break;
844cabdff1aSopenharmony_ci    case 2:
845cabdff1aSopenharmony_ci        {
846cabdff1aSopenharmony_ci            int arr1[16];
847cabdff1aSopenharmony_ci            int arr2[16];
848cabdff1aSopenharmony_ci            uint8_t *top = frame->data[plane] + FFMAX(ay - 1, 0) * frame->linesize[plane] + ax;
849cabdff1aSopenharmony_ci            uint8_t *left = frame->data[plane] + ay * frame->linesize[plane] + FFMAX(ax - 1, 0);
850cabdff1aSopenharmony_ci            int bottommost = frame->data[plane][(ay + size - 1) * frame->linesize[plane] + FFMAX(ax - 1, 0)];
851cabdff1aSopenharmony_ci            int rightmost = frame->data[plane][FFMAX(ay - 1, 0) * frame->linesize[plane] + ax + size - 1];
852cabdff1aSopenharmony_ci            int avg = (bottommost + rightmost + 1) / 2 + 2 * av_clip(get_se_golomb(gb), -(1<<16), 1<<16);
853cabdff1aSopenharmony_ci            int r6 = adjust(avg - bottommost, size);
854cabdff1aSopenharmony_ci            int r9 = adjust(avg - rightmost, size);
855cabdff1aSopenharmony_ci            int shift = adjust(size, size) == 8 ? 3 : 2;
856cabdff1aSopenharmony_ci            uint8_t *block;
857cabdff1aSopenharmony_ci
858cabdff1aSopenharmony_ci            for (int x = 0; x < size; x++) {
859cabdff1aSopenharmony_ci                int val = top[x];
860cabdff1aSopenharmony_ci                arr1[x] = adjust(((bottommost - val) * (1 << shift)) + r6 * (x + 1), size);
861cabdff1aSopenharmony_ci            }
862cabdff1aSopenharmony_ci
863cabdff1aSopenharmony_ci            for (int y = 0; y < size; y++) {
864cabdff1aSopenharmony_ci                int val = left[y * frame->linesize[plane]];
865cabdff1aSopenharmony_ci                arr2[y] = adjust(((rightmost - val) * (1 << shift)) + r9 * (y + 1), size);
866cabdff1aSopenharmony_ci            }
867cabdff1aSopenharmony_ci
868cabdff1aSopenharmony_ci            block = frame->data[plane] + ay * frame->linesize[plane] + ax;
869cabdff1aSopenharmony_ci            for (int y = 0; y < size; y++) {
870cabdff1aSopenharmony_ci                for (int x = 0; x < size; x++) {
871cabdff1aSopenharmony_ci                    block[x] = (((top[x] + left[0] + ((arr1[x] * (y + 1) +
872cabdff1aSopenharmony_ci                                                       arr2[y] * (x + 1)) >> 2 * shift)) + 1) / 2) & 0xFF;
873cabdff1aSopenharmony_ci                }
874cabdff1aSopenharmony_ci                block += frame->linesize[plane];
875cabdff1aSopenharmony_ci                left  += frame->linesize[plane];
876cabdff1aSopenharmony_ci            }
877cabdff1aSopenharmony_ci        }
878cabdff1aSopenharmony_ci        break;
879cabdff1aSopenharmony_ci    case 3:
880cabdff1aSopenharmony_ci        {
881cabdff1aSopenharmony_ci            uint8_t fill;
882cabdff1aSopenharmony_ci
883cabdff1aSopenharmony_ci            if (ax == 0 && ay == 0) {
884cabdff1aSopenharmony_ci                fill = 0x80;
885cabdff1aSopenharmony_ci            } else if (ax >= 1 && ay >= 1) {
886cabdff1aSopenharmony_ci                int left = block_sum(frame->data[plane] + ay * frame->linesize[plane] + ax - 1,
887cabdff1aSopenharmony_ci                                     1, size, frame->linesize[plane]);
888cabdff1aSopenharmony_ci                int top  = block_sum(frame->data[plane] + (ay - 1) * frame->linesize[plane] + ax,
889cabdff1aSopenharmony_ci                                     size, 1, frame->linesize[plane]);
890cabdff1aSopenharmony_ci
891cabdff1aSopenharmony_ci                fill = ((left + top) * 2 / (2 * size) + 1) / 2;
892cabdff1aSopenharmony_ci            } else if (ax >= 1) {
893cabdff1aSopenharmony_ci                fill = (block_sum(frame->data[plane] + ay * frame->linesize[plane] + ax - 1,
894cabdff1aSopenharmony_ci                                  1, size, frame->linesize[plane]) * 2 / size + 1) / 2;
895cabdff1aSopenharmony_ci            } else if (ay >= 1) {
896cabdff1aSopenharmony_ci                fill = (block_sum(frame->data[plane] + (ay - 1) * frame->linesize[plane] + ax,
897cabdff1aSopenharmony_ci                                  size, 1, frame->linesize[plane]) * 2 / size + 1) / 2;
898cabdff1aSopenharmony_ci            } else {
899cabdff1aSopenharmony_ci                return -1;
900cabdff1aSopenharmony_ci            }
901cabdff1aSopenharmony_ci
902cabdff1aSopenharmony_ci            block_fill_simple(frame->data[plane] + ay * frame->linesize[plane] + ax,
903cabdff1aSopenharmony_ci                              size, frame->linesize[plane], fill);
904cabdff1aSopenharmony_ci        }
905cabdff1aSopenharmony_ci        break;
906cabdff1aSopenharmony_ci    case 4:
907cabdff1aSopenharmony_ci        block_fill(frame->data[plane], size, frame->linesize[plane], w, h, ax, ay, pick_4);
908cabdff1aSopenharmony_ci        break;
909cabdff1aSopenharmony_ci    case 5:
910cabdff1aSopenharmony_ci        block_fill(frame->data[plane], size, frame->linesize[plane], w, h, ax, ay, pick_5);
911cabdff1aSopenharmony_ci        break;
912cabdff1aSopenharmony_ci    case 6:
913cabdff1aSopenharmony_ci        block_fill(frame->data[plane], size, frame->linesize[plane], w, h, ax, ay, pick_6);
914cabdff1aSopenharmony_ci        break;
915cabdff1aSopenharmony_ci    case 7:
916cabdff1aSopenharmony_ci        block_fill(frame->data[plane], size, frame->linesize[plane], w, h, ax, ay, pick_7);
917cabdff1aSopenharmony_ci        break;
918cabdff1aSopenharmony_ci    case 8:
919cabdff1aSopenharmony_ci        block_fill(frame->data[plane], size, frame->linesize[plane], w, h, ax, ay, pick_8);
920cabdff1aSopenharmony_ci        break;
921cabdff1aSopenharmony_ci    }
922cabdff1aSopenharmony_ci
923cabdff1aSopenharmony_ci    if (add_coeffs)
924cabdff1aSopenharmony_ci        ret = add_coefficients(avctx, frame, ax, ay, size, plane);
925cabdff1aSopenharmony_ci
926cabdff1aSopenharmony_ci    return ret;
927cabdff1aSopenharmony_ci}
928cabdff1aSopenharmony_ci
929cabdff1aSopenharmony_cistatic int get_prediction(AVCodecContext *avctx, int x, int y, int size)
930cabdff1aSopenharmony_ci{
931cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
932cabdff1aSopenharmony_ci    GetBitContext *gb = &s->gb;
933cabdff1aSopenharmony_ci    int index = (y & 0xC) | (x / 4 % 4);
934cabdff1aSopenharmony_ci
935cabdff1aSopenharmony_ci    uint8_t val = FFMIN(s->pre[index], index % 4 == 0 ? 9 : s->pre[index + 3]);
936cabdff1aSopenharmony_ci    if (val == 9)
937cabdff1aSopenharmony_ci        val = 3;
938cabdff1aSopenharmony_ci
939cabdff1aSopenharmony_ci    if (!get_bits1(gb)) {
940cabdff1aSopenharmony_ci        int x = get_bits(gb, 3);
941cabdff1aSopenharmony_ci        val = x + (x >= val ? 1 : 0);
942cabdff1aSopenharmony_ci    }
943cabdff1aSopenharmony_ci
944cabdff1aSopenharmony_ci    s->pre[index + 4] = val;
945cabdff1aSopenharmony_ci    if (size == 8)
946cabdff1aSopenharmony_ci        s->pre[index + 5] = s->pre[index + 8] = s->pre[index + 9] = val;
947cabdff1aSopenharmony_ci
948cabdff1aSopenharmony_ci    return val;
949cabdff1aSopenharmony_ci}
950cabdff1aSopenharmony_ci
951cabdff1aSopenharmony_cistatic int process_block(AVCodecContext *avctx, AVFrame *frame,
952cabdff1aSopenharmony_ci                         int x, int y, int pmode, int has_coeffs, int plane)
953cabdff1aSopenharmony_ci{
954cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
955cabdff1aSopenharmony_ci    GetBitContext *gb = &s->gb;
956cabdff1aSopenharmony_ci    int tmp, ret;
957cabdff1aSopenharmony_ci
958cabdff1aSopenharmony_ci    if (!has_coeffs) {
959cabdff1aSopenharmony_ci        if (pmode < 0)
960cabdff1aSopenharmony_ci            pmode = get_prediction(avctx, x, y, 8);
961cabdff1aSopenharmony_ci        return predict_intra(avctx, frame, x, y, pmode, 0, 8, plane);
962cabdff1aSopenharmony_ci    }
963cabdff1aSopenharmony_ci
964cabdff1aSopenharmony_ci    tmp = get_ue_golomb_31(gb);
965cabdff1aSopenharmony_ci    if ((unsigned)tmp > FF_ARRAY_ELEMS(block4x4_coefficients_tab))
966cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
967cabdff1aSopenharmony_ci
968cabdff1aSopenharmony_ci    if (tmp == 0) {
969cabdff1aSopenharmony_ci        if (pmode < 0)
970cabdff1aSopenharmony_ci            pmode = get_prediction(avctx, x, y, 8);
971cabdff1aSopenharmony_ci        ret = predict_intra(avctx, frame, x, y, pmode, 1, 8, plane);
972cabdff1aSopenharmony_ci    } else {
973cabdff1aSopenharmony_ci        int flags = block4x4_coefficients_tab[tmp - 1];
974cabdff1aSopenharmony_ci
975cabdff1aSopenharmony_ci        for (int by = y; by < y + 8; by += 4) {
976cabdff1aSopenharmony_ci            for (int bx = x; bx < x + 8; bx += 4) {
977cabdff1aSopenharmony_ci                int new_pmode = pmode;
978cabdff1aSopenharmony_ci
979cabdff1aSopenharmony_ci                if (new_pmode < 0)
980cabdff1aSopenharmony_ci                    new_pmode = get_prediction(avctx, bx, by, 4);
981cabdff1aSopenharmony_ci                ret = predict_intra(avctx, frame, bx, by, new_pmode, flags & 1, 4, plane);
982cabdff1aSopenharmony_ci                if (ret < 0)
983cabdff1aSopenharmony_ci                    return ret;
984cabdff1aSopenharmony_ci                flags >>= 1;
985cabdff1aSopenharmony_ci            }
986cabdff1aSopenharmony_ci        }
987cabdff1aSopenharmony_ci    }
988cabdff1aSopenharmony_ci
989cabdff1aSopenharmony_ci    return ret;
990cabdff1aSopenharmony_ci}
991cabdff1aSopenharmony_ci
992cabdff1aSopenharmony_cistatic int decode_macroblock(AVCodecContext *avctx, AVFrame *frame,
993cabdff1aSopenharmony_ci                             int x, int y, int predict)
994cabdff1aSopenharmony_ci{
995cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
996cabdff1aSopenharmony_ci    GetBitContext *gb = &s->gb;
997cabdff1aSopenharmony_ci    int flags, pmode_uv, idx = get_ue_golomb(gb);
998cabdff1aSopenharmony_ci    int ret = 0;
999cabdff1aSopenharmony_ci
1000cabdff1aSopenharmony_ci    if (idx < 0 || idx >= FF_ARRAY_ELEMS(block8x8_coefficients_tab))
1001cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
1002cabdff1aSopenharmony_ci
1003cabdff1aSopenharmony_ci    flags = block8x8_coefficients_tab[idx];
1004cabdff1aSopenharmony_ci
1005cabdff1aSopenharmony_ci    if (predict) {
1006cabdff1aSopenharmony_ci        ret = process_block(avctx, frame, x, y, -1, flags & 1, 0);
1007cabdff1aSopenharmony_ci        if (ret < 0)
1008cabdff1aSopenharmony_ci            return ret;
1009cabdff1aSopenharmony_ci        flags >>= 1;
1010cabdff1aSopenharmony_ci        ret = process_block(avctx, frame, x + 8, y, -1, flags & 1, 0);
1011cabdff1aSopenharmony_ci        if (ret < 0)
1012cabdff1aSopenharmony_ci            return ret;
1013cabdff1aSopenharmony_ci        flags >>= 1;
1014cabdff1aSopenharmony_ci        ret = process_block(avctx, frame, x, y + 8, -1, flags & 1, 0);
1015cabdff1aSopenharmony_ci        if (ret < 0)
1016cabdff1aSopenharmony_ci            return ret;
1017cabdff1aSopenharmony_ci        flags >>= 1;
1018cabdff1aSopenharmony_ci        ret = process_block(avctx, frame, x + 8, y + 8, -1, flags & 1, 0);
1019cabdff1aSopenharmony_ci        if (ret < 0)
1020cabdff1aSopenharmony_ci            return ret;
1021cabdff1aSopenharmony_ci        flags >>= 1;
1022cabdff1aSopenharmony_ci    } else {
1023cabdff1aSopenharmony_ci        int pmode = get_bits(gb, 3);
1024cabdff1aSopenharmony_ci
1025cabdff1aSopenharmony_ci        if (pmode == 2) {
1026cabdff1aSopenharmony_ci            ret = predict_intra(avctx, frame, x, y, pmode, 0, 16, 0);
1027cabdff1aSopenharmony_ci            if (ret < 0)
1028cabdff1aSopenharmony_ci                return ret;
1029cabdff1aSopenharmony_ci            pmode = 9;
1030cabdff1aSopenharmony_ci        }
1031cabdff1aSopenharmony_ci
1032cabdff1aSopenharmony_ci        ret = process_block(avctx, frame, x, y, pmode, flags & 1, 0);
1033cabdff1aSopenharmony_ci        if (ret < 0)
1034cabdff1aSopenharmony_ci            return ret;
1035cabdff1aSopenharmony_ci        flags >>= 1;
1036cabdff1aSopenharmony_ci        ret = process_block(avctx, frame, x + 8, y, pmode, flags & 1, 0);
1037cabdff1aSopenharmony_ci        if (ret < 0)
1038cabdff1aSopenharmony_ci            return ret;
1039cabdff1aSopenharmony_ci        flags >>= 1;
1040cabdff1aSopenharmony_ci        ret = process_block(avctx, frame, x, y + 8, pmode, flags & 1, 0);
1041cabdff1aSopenharmony_ci        if (ret < 0)
1042cabdff1aSopenharmony_ci            return ret;
1043cabdff1aSopenharmony_ci        flags >>= 1;
1044cabdff1aSopenharmony_ci        ret = process_block(avctx, frame, x + 8, y + 8, pmode, flags & 1, 0);
1045cabdff1aSopenharmony_ci        if (ret < 0)
1046cabdff1aSopenharmony_ci            return ret;
1047cabdff1aSopenharmony_ci        flags >>= 1;
1048cabdff1aSopenharmony_ci    }
1049cabdff1aSopenharmony_ci
1050cabdff1aSopenharmony_ci    pmode_uv = get_bits(gb, 3);
1051cabdff1aSopenharmony_ci    if (pmode_uv == 2) {
1052cabdff1aSopenharmony_ci        ret = predict_intra(avctx, frame, x >> 1, y >> 1, pmode_uv, 0, 8, 1 + !s->moflex);
1053cabdff1aSopenharmony_ci        if (ret < 0)
1054cabdff1aSopenharmony_ci            return ret;
1055cabdff1aSopenharmony_ci        ret = predict_intra(avctx, frame, x >> 1, y >> 1, pmode_uv, 0, 8, 2 - !s->moflex);
1056cabdff1aSopenharmony_ci        if (ret < 0)
1057cabdff1aSopenharmony_ci            return ret;
1058cabdff1aSopenharmony_ci        pmode_uv = 9;
1059cabdff1aSopenharmony_ci    }
1060cabdff1aSopenharmony_ci
1061cabdff1aSopenharmony_ci    ret = process_block(avctx, frame, x >> 1, y >> 1, pmode_uv, flags & 1, 1 + !s->moflex);
1062cabdff1aSopenharmony_ci    if (ret < 0)
1063cabdff1aSopenharmony_ci        return ret;
1064cabdff1aSopenharmony_ci    flags >>= 1;
1065cabdff1aSopenharmony_ci    ret = process_block(avctx, frame, x >> 1, y >> 1, pmode_uv, flags & 1, 2 - !s->moflex);
1066cabdff1aSopenharmony_ci    if (ret < 0)
1067cabdff1aSopenharmony_ci        return ret;
1068cabdff1aSopenharmony_ci
1069cabdff1aSopenharmony_ci    return 0;
1070cabdff1aSopenharmony_ci}
1071cabdff1aSopenharmony_ci
1072cabdff1aSopenharmony_cistatic int get_index(int x)
1073cabdff1aSopenharmony_ci{
1074cabdff1aSopenharmony_ci    return x == 16 ? 0 : x == 8 ? 1 : x == 4 ? 2 : x == 2 ? 3 : 0;
1075cabdff1aSopenharmony_ci}
1076cabdff1aSopenharmony_ci
1077cabdff1aSopenharmony_cistatic int predict_motion(AVCodecContext *avctx,
1078cabdff1aSopenharmony_ci                          int width, int height, int index,
1079cabdff1aSopenharmony_ci                          int offsetm, int offsetx, int offsety)
1080cabdff1aSopenharmony_ci{
1081cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
1082cabdff1aSopenharmony_ci    MotionXY *motion = s->motion;
1083cabdff1aSopenharmony_ci    GetBitContext *gb = &s->gb;
1084cabdff1aSopenharmony_ci    int fheight = avctx->height;
1085cabdff1aSopenharmony_ci    int fwidth = avctx->width;
1086cabdff1aSopenharmony_ci
1087cabdff1aSopenharmony_ci    if (index <= 5) {
1088cabdff1aSopenharmony_ci        int sidx = -FFMAX(1, index) + s->current_pic;
1089cabdff1aSopenharmony_ci        MotionXY mv = s->motion[0];
1090cabdff1aSopenharmony_ci
1091cabdff1aSopenharmony_ci        if (sidx < 0)
1092cabdff1aSopenharmony_ci            sidx += 6;
1093cabdff1aSopenharmony_ci
1094cabdff1aSopenharmony_ci        if (index > 0) {
1095cabdff1aSopenharmony_ci            mv.x = mv.x + (unsigned)get_se_golomb(gb);
1096cabdff1aSopenharmony_ci            mv.y = mv.y + (unsigned)get_se_golomb(gb);
1097cabdff1aSopenharmony_ci        }
1098cabdff1aSopenharmony_ci        if (mv.x >= INT_MAX || mv.y >= INT_MAX)
1099cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1100cabdff1aSopenharmony_ci
1101cabdff1aSopenharmony_ci        motion[offsetm].x = mv.x;
1102cabdff1aSopenharmony_ci        motion[offsetm].y = mv.y;
1103cabdff1aSopenharmony_ci
1104cabdff1aSopenharmony_ci        for (int i = 0; i < 3; i++) {
1105cabdff1aSopenharmony_ci            int method, src_linesize, dst_linesize;
1106cabdff1aSopenharmony_ci            uint8_t *src, *dst;
1107cabdff1aSopenharmony_ci
1108cabdff1aSopenharmony_ci            if (i == 1) {
1109cabdff1aSopenharmony_ci                offsetx = offsetx >> 1;
1110cabdff1aSopenharmony_ci                offsety = offsety >> 1;
1111cabdff1aSopenharmony_ci                mv.x = mv.x >> 1;
1112cabdff1aSopenharmony_ci                mv.y = mv.y >> 1;
1113cabdff1aSopenharmony_ci                width = width >> 1;
1114cabdff1aSopenharmony_ci                height = height >> 1;
1115cabdff1aSopenharmony_ci                fwidth = fwidth >> 1;
1116cabdff1aSopenharmony_ci                fheight = fheight >> 1;
1117cabdff1aSopenharmony_ci            }
1118cabdff1aSopenharmony_ci
1119cabdff1aSopenharmony_ci            av_assert0(s->pic[sidx]);
1120cabdff1aSopenharmony_ci            av_assert0(s->pic[s->current_pic]);
1121cabdff1aSopenharmony_ci            av_assert0(s->pic[s->current_pic]->data[i]);
1122cabdff1aSopenharmony_ci            if (!s->pic[sidx]->data[i])
1123cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
1124cabdff1aSopenharmony_ci
1125cabdff1aSopenharmony_ci            method = (mv.x & 1) | ((mv.y & 1) << 1);
1126cabdff1aSopenharmony_ci            src_linesize = s->pic[sidx]->linesize[i];
1127cabdff1aSopenharmony_ci            dst_linesize = s->pic[s->current_pic]->linesize[i];
1128cabdff1aSopenharmony_ci            dst = s->pic[s->current_pic]->data[i] + offsetx + offsety * dst_linesize;
1129cabdff1aSopenharmony_ci
1130cabdff1aSopenharmony_ci            if (offsetx + (mv.x >> 1) < 0 ||
1131cabdff1aSopenharmony_ci                offsety + (mv.y >> 1) < 0 ||
1132cabdff1aSopenharmony_ci                offsetx + width  + (mv.x + 1 >> 1) > fwidth ||
1133cabdff1aSopenharmony_ci                offsety + height + (mv.y + 1 >> 1) > fheight)
1134cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
1135cabdff1aSopenharmony_ci
1136cabdff1aSopenharmony_ci            switch (method) {
1137cabdff1aSopenharmony_ci            case 0:
1138cabdff1aSopenharmony_ci                src = s->pic[sidx]->data[i] + offsetx + (mv.x >> 1) +
1139cabdff1aSopenharmony_ci                               (offsety + (mv.y >> 1)) * src_linesize;
1140cabdff1aSopenharmony_ci                for (int y = 0; y < height; y++) {
1141cabdff1aSopenharmony_ci                    for (int x = 0; x < width; x++)
1142cabdff1aSopenharmony_ci                        dst[x] = src[x];
1143cabdff1aSopenharmony_ci                    dst += dst_linesize;
1144cabdff1aSopenharmony_ci                    src += src_linesize;
1145cabdff1aSopenharmony_ci                }
1146cabdff1aSopenharmony_ci                break;
1147cabdff1aSopenharmony_ci            case 1:
1148cabdff1aSopenharmony_ci                src = s->pic[sidx]->data[i] + offsetx + (mv.x >> 1) +
1149cabdff1aSopenharmony_ci                               (offsety + (mv.y >> 1)) * src_linesize;
1150cabdff1aSopenharmony_ci                for (int y = 0; y < height; y++) {
1151cabdff1aSopenharmony_ci                    for (int x = 0; x < width; x++) {
1152cabdff1aSopenharmony_ci                        dst[x] = (uint8_t)((src[x] >> 1) + (src[x + 1] >> 1));
1153cabdff1aSopenharmony_ci                    }
1154cabdff1aSopenharmony_ci
1155cabdff1aSopenharmony_ci                    dst += dst_linesize;
1156cabdff1aSopenharmony_ci                    src += src_linesize;
1157cabdff1aSopenharmony_ci                }
1158cabdff1aSopenharmony_ci                break;
1159cabdff1aSopenharmony_ci            case 2:
1160cabdff1aSopenharmony_ci                src = s->pic[sidx]->data[i] + offsetx + (mv.x >> 1) +
1161cabdff1aSopenharmony_ci                               (offsety + (mv.y >> 1)) * src_linesize;
1162cabdff1aSopenharmony_ci                for (int y = 0; y < height; y++) {
1163cabdff1aSopenharmony_ci                    for (int x = 0; x < width; x++) {
1164cabdff1aSopenharmony_ci                        dst[x] = (uint8_t)((src[x] >> 1) + (src[x + src_linesize] >> 1));
1165cabdff1aSopenharmony_ci                    }
1166cabdff1aSopenharmony_ci
1167cabdff1aSopenharmony_ci                    dst += dst_linesize;
1168cabdff1aSopenharmony_ci                    src += src_linesize;
1169cabdff1aSopenharmony_ci                }
1170cabdff1aSopenharmony_ci                break;
1171cabdff1aSopenharmony_ci            case 3:
1172cabdff1aSopenharmony_ci                src = s->pic[sidx]->data[i] + offsetx + (mv.x >> 1) +
1173cabdff1aSopenharmony_ci                               (offsety + (mv.y >> 1)) * src_linesize;
1174cabdff1aSopenharmony_ci                for (int y = 0; y < height; y++) {
1175cabdff1aSopenharmony_ci                    for (int x = 0; x < width; x++) {
1176cabdff1aSopenharmony_ci                        dst[x] = (uint8_t)((((src[x] >> 1) + (src[x + 1] >> 1)) >> 1) +
1177cabdff1aSopenharmony_ci                                           (((src[x + src_linesize] >> 1) + (src[x + 1 + src_linesize] >> 1)) >> 1));
1178cabdff1aSopenharmony_ci                    }
1179cabdff1aSopenharmony_ci
1180cabdff1aSopenharmony_ci                    dst += dst_linesize;
1181cabdff1aSopenharmony_ci                    src += src_linesize;
1182cabdff1aSopenharmony_ci                }
1183cabdff1aSopenharmony_ci                break;
1184cabdff1aSopenharmony_ci            }
1185cabdff1aSopenharmony_ci        }
1186cabdff1aSopenharmony_ci    } else {
1187cabdff1aSopenharmony_ci        int tidx;
1188cabdff1aSopenharmony_ci        int adjx = index == 8 ? 0 :  width / 2;
1189cabdff1aSopenharmony_ci        int adjy = index == 8 ? height / 2 : 0;
1190cabdff1aSopenharmony_ci
1191cabdff1aSopenharmony_ci        width  = width  - adjx;
1192cabdff1aSopenharmony_ci        height = height - adjy;
1193cabdff1aSopenharmony_ci        tidx = get_index(height) * 4 + get_index(width);
1194cabdff1aSopenharmony_ci
1195cabdff1aSopenharmony_ci        for (int i = 0; i < 2; i++) {
1196cabdff1aSopenharmony_ci            int ret, idx2;
1197cabdff1aSopenharmony_ci
1198cabdff1aSopenharmony_ci            idx2 = get_vlc2(gb, mv_vlc[s->moflex][tidx].table,
1199cabdff1aSopenharmony_ci                            MOBI_MV_VLC_BITS, 1);
1200cabdff1aSopenharmony_ci
1201cabdff1aSopenharmony_ci            ret = predict_motion(avctx, width, height, idx2,
1202cabdff1aSopenharmony_ci                                 offsetm, offsetx + i * adjx, offsety + i * adjy);
1203cabdff1aSopenharmony_ci            if (ret < 0)
1204cabdff1aSopenharmony_ci                return ret;
1205cabdff1aSopenharmony_ci        }
1206cabdff1aSopenharmony_ci    }
1207cabdff1aSopenharmony_ci
1208cabdff1aSopenharmony_ci    return 0;
1209cabdff1aSopenharmony_ci}
1210cabdff1aSopenharmony_ci
1211cabdff1aSopenharmony_cistatic int mobiclip_decode(AVCodecContext *avctx, AVFrame *rframe,
1212cabdff1aSopenharmony_ci                           int *got_frame, AVPacket *pkt)
1213cabdff1aSopenharmony_ci{
1214cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
1215cabdff1aSopenharmony_ci    GetBitContext *gb = &s->gb;
1216cabdff1aSopenharmony_ci    AVFrame *frame = s->pic[s->current_pic];
1217cabdff1aSopenharmony_ci    int ret;
1218cabdff1aSopenharmony_ci
1219cabdff1aSopenharmony_ci    av_fast_padded_malloc(&s->bitstream, &s->bitstream_size,
1220cabdff1aSopenharmony_ci                          pkt->size);
1221cabdff1aSopenharmony_ci
1222cabdff1aSopenharmony_ci    if ((ret = ff_reget_buffer(avctx, frame, 0)) < 0)
1223cabdff1aSopenharmony_ci        return ret;
1224cabdff1aSopenharmony_ci
1225cabdff1aSopenharmony_ci    s->bdsp.bswap16_buf((uint16_t *)s->bitstream,
1226cabdff1aSopenharmony_ci                        (uint16_t *)pkt->data,
1227cabdff1aSopenharmony_ci                        (pkt->size + 1) >> 1);
1228cabdff1aSopenharmony_ci
1229cabdff1aSopenharmony_ci    ret = init_get_bits8(gb, s->bitstream, FFALIGN(pkt->size, 2));
1230cabdff1aSopenharmony_ci    if (ret < 0)
1231cabdff1aSopenharmony_ci        return ret;
1232cabdff1aSopenharmony_ci
1233cabdff1aSopenharmony_ci    if (get_bits1(gb)) {
1234cabdff1aSopenharmony_ci        frame->pict_type = AV_PICTURE_TYPE_I;
1235cabdff1aSopenharmony_ci        frame->key_frame = 1;
1236cabdff1aSopenharmony_ci        s->moflex = get_bits1(gb);
1237cabdff1aSopenharmony_ci        s->dct_tab_idx = get_bits1(gb);
1238cabdff1aSopenharmony_ci
1239cabdff1aSopenharmony_ci        ret = setup_qtables(avctx, get_bits(gb, 6));
1240cabdff1aSopenharmony_ci        if (ret < 0)
1241cabdff1aSopenharmony_ci            return ret;
1242cabdff1aSopenharmony_ci
1243cabdff1aSopenharmony_ci        for (int y = 0; y < avctx->height; y += 16) {
1244cabdff1aSopenharmony_ci            for (int x = 0; x < avctx->width; x += 16) {
1245cabdff1aSopenharmony_ci                ret = decode_macroblock(avctx, frame, x, y, get_bits1(gb));
1246cabdff1aSopenharmony_ci                if (ret < 0)
1247cabdff1aSopenharmony_ci                    return ret;
1248cabdff1aSopenharmony_ci            }
1249cabdff1aSopenharmony_ci        }
1250cabdff1aSopenharmony_ci    } else {
1251cabdff1aSopenharmony_ci        MotionXY *motion = s->motion;
1252cabdff1aSopenharmony_ci
1253cabdff1aSopenharmony_ci        memset(motion, 0, s->motion_size);
1254cabdff1aSopenharmony_ci
1255cabdff1aSopenharmony_ci        frame->pict_type = AV_PICTURE_TYPE_P;
1256cabdff1aSopenharmony_ci        frame->key_frame = 0;
1257cabdff1aSopenharmony_ci        s->dct_tab_idx = 0;
1258cabdff1aSopenharmony_ci
1259cabdff1aSopenharmony_ci        ret = setup_qtables(avctx, s->quantizer + (int64_t)get_se_golomb(gb));
1260cabdff1aSopenharmony_ci        if (ret < 0)
1261cabdff1aSopenharmony_ci            return ret;
1262cabdff1aSopenharmony_ci
1263cabdff1aSopenharmony_ci        for (int y = 0; y < avctx->height; y += 16) {
1264cabdff1aSopenharmony_ci            for (int x = 0; x < avctx->width; x += 16) {
1265cabdff1aSopenharmony_ci                int idx;
1266cabdff1aSopenharmony_ci
1267cabdff1aSopenharmony_ci                motion[0].x = mid_pred(motion[x / 16 + 1].x, motion[x / 16 + 2].x, motion[x / 16 + 3].x);
1268cabdff1aSopenharmony_ci                motion[0].y = mid_pred(motion[x / 16 + 1].y, motion[x / 16 + 2].y, motion[x / 16 + 3].y);
1269cabdff1aSopenharmony_ci                motion[x / 16 + 2].x = 0;
1270cabdff1aSopenharmony_ci                motion[x / 16 + 2].y = 0;
1271cabdff1aSopenharmony_ci
1272cabdff1aSopenharmony_ci                idx = get_vlc2(gb, mv_vlc[s->moflex][0].table,
1273cabdff1aSopenharmony_ci                                   MOBI_MV_VLC_BITS, 1);
1274cabdff1aSopenharmony_ci
1275cabdff1aSopenharmony_ci                if (idx == 6 || idx == 7) {
1276cabdff1aSopenharmony_ci                    ret = decode_macroblock(avctx, frame, x, y, idx == 7);
1277cabdff1aSopenharmony_ci                    if (ret < 0)
1278cabdff1aSopenharmony_ci                        return ret;
1279cabdff1aSopenharmony_ci                } else {
1280cabdff1aSopenharmony_ci                    int flags, idx2;
1281cabdff1aSopenharmony_ci                    ret = predict_motion(avctx, 16, 16, idx, x / 16 + 2, x, y);
1282cabdff1aSopenharmony_ci                    if (ret < 0)
1283cabdff1aSopenharmony_ci                        return ret;
1284cabdff1aSopenharmony_ci                    idx2 = get_ue_golomb(gb);
1285cabdff1aSopenharmony_ci                    if (idx2 >= FF_ARRAY_ELEMS(pframe_block8x8_coefficients_tab))
1286cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
1287cabdff1aSopenharmony_ci                    flags = pframe_block8x8_coefficients_tab[idx2];
1288cabdff1aSopenharmony_ci
1289cabdff1aSopenharmony_ci                    for (int sy = y; sy < y + 16; sy += 8) {
1290cabdff1aSopenharmony_ci                        for (int sx = x; sx < x + 16; sx += 8) {
1291cabdff1aSopenharmony_ci                            if (flags & 1)
1292cabdff1aSopenharmony_ci                                add_pframe_coefficients(avctx, frame, sx, sy, 8, 0);
1293cabdff1aSopenharmony_ci                            flags >>= 1;
1294cabdff1aSopenharmony_ci                        }
1295cabdff1aSopenharmony_ci                    }
1296cabdff1aSopenharmony_ci
1297cabdff1aSopenharmony_ci                    if (flags & 1)
1298cabdff1aSopenharmony_ci                        add_pframe_coefficients(avctx, frame, x >> 1, y >> 1, 8, 1 + !s->moflex);
1299cabdff1aSopenharmony_ci                    flags >>= 1;
1300cabdff1aSopenharmony_ci                    if (flags & 1)
1301cabdff1aSopenharmony_ci                        add_pframe_coefficients(avctx, frame, x >> 1, y >> 1, 8, 2 - !s->moflex);
1302cabdff1aSopenharmony_ci                }
1303cabdff1aSopenharmony_ci            }
1304cabdff1aSopenharmony_ci        }
1305cabdff1aSopenharmony_ci    }
1306cabdff1aSopenharmony_ci
1307cabdff1aSopenharmony_ci    if (!s->moflex)
1308cabdff1aSopenharmony_ci        avctx->colorspace = AVCOL_SPC_YCGCO;
1309cabdff1aSopenharmony_ci
1310cabdff1aSopenharmony_ci    s->current_pic = (s->current_pic + 1) % 6;
1311cabdff1aSopenharmony_ci    ret = av_frame_ref(rframe, frame);
1312cabdff1aSopenharmony_ci    if (ret < 0)
1313cabdff1aSopenharmony_ci        return ret;
1314cabdff1aSopenharmony_ci    *got_frame = 1;
1315cabdff1aSopenharmony_ci
1316cabdff1aSopenharmony_ci    return 0;
1317cabdff1aSopenharmony_ci}
1318cabdff1aSopenharmony_ci
1319cabdff1aSopenharmony_cistatic void mobiclip_flush(AVCodecContext *avctx)
1320cabdff1aSopenharmony_ci{
1321cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
1322cabdff1aSopenharmony_ci
1323cabdff1aSopenharmony_ci    for (int i = 0; i < 6; i++)
1324cabdff1aSopenharmony_ci        av_frame_unref(s->pic[i]);
1325cabdff1aSopenharmony_ci}
1326cabdff1aSopenharmony_ci
1327cabdff1aSopenharmony_cistatic av_cold int mobiclip_close(AVCodecContext *avctx)
1328cabdff1aSopenharmony_ci{
1329cabdff1aSopenharmony_ci    MobiClipContext *s = avctx->priv_data;
1330cabdff1aSopenharmony_ci
1331cabdff1aSopenharmony_ci    av_freep(&s->bitstream);
1332cabdff1aSopenharmony_ci    s->bitstream_size = 0;
1333cabdff1aSopenharmony_ci    av_freep(&s->motion);
1334cabdff1aSopenharmony_ci    s->motion_size = 0;
1335cabdff1aSopenharmony_ci
1336cabdff1aSopenharmony_ci    for (int i = 0; i < 6; i++) {
1337cabdff1aSopenharmony_ci        av_frame_free(&s->pic[i]);
1338cabdff1aSopenharmony_ci    }
1339cabdff1aSopenharmony_ci
1340cabdff1aSopenharmony_ci    return 0;
1341cabdff1aSopenharmony_ci}
1342cabdff1aSopenharmony_ci
1343cabdff1aSopenharmony_ciconst FFCodec ff_mobiclip_decoder = {
1344cabdff1aSopenharmony_ci    .p.name         = "mobiclip",
1345cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("MobiClip Video"),
1346cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
1347cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_MOBICLIP,
1348cabdff1aSopenharmony_ci    .priv_data_size = sizeof(MobiClipContext),
1349cabdff1aSopenharmony_ci    .init           = mobiclip_init,
1350cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(mobiclip_decode),
1351cabdff1aSopenharmony_ci    .flush          = mobiclip_flush,
1352cabdff1aSopenharmony_ci    .close          = mobiclip_close,
1353cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1,
1354cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
1355cabdff1aSopenharmony_ci};
1356