/src/ffmpeg/libavcodec/arbc.c
Line | Count | Source |
1 | | /* |
2 | | * Gryphon's Anim Compressor decoder |
3 | | * Copyright (c) 2019 Paul B Mahol |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
7 | | * FFmpeg is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * FFmpeg is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with FFmpeg; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #include "libavutil/attributes.h" |
23 | | #include "libavutil/internal.h" |
24 | | #include "libavutil/intreadwrite.h" |
25 | | |
26 | | #include "avcodec.h" |
27 | | #include "bytestream.h" |
28 | | #include "codec_internal.h" |
29 | | #include "decode.h" |
30 | | |
31 | | typedef struct ARBCContext { |
32 | | GetByteContext gb; |
33 | | |
34 | | AVFrame *prev_frame; |
35 | | } ARBCContext; |
36 | | |
37 | | static int fill_tile4(AVCodecContext *avctx, int color, AVFrame *frame) |
38 | 40.3k | { |
39 | 40.3k | ARBCContext *s = avctx->priv_data; |
40 | 40.3k | GetByteContext *gb = &s->gb; |
41 | 40.3k | int nb_tiles = bytestream2_get_le16(gb); |
42 | 40.3k | int h = avctx->height - 1; |
43 | 40.3k | int pixels_overwritten = 0; |
44 | | |
45 | 40.3k | if ((avctx->width / 4 + 1) * (avctx->height / 4 + 1) < nb_tiles) |
46 | 23.2k | return 0; |
47 | | |
48 | 4.15M | for (int i = 0; i < nb_tiles; i++) { |
49 | 4.13M | int y = bytestream2_get_byte(gb); |
50 | 4.13M | int x = bytestream2_get_byte(gb); |
51 | 4.13M | uint16_t mask = bytestream2_get_le16(gb); |
52 | 4.13M | int start_y = y * 4, start_x = x * 4; |
53 | 4.13M | int end_y = start_y + 4, end_x = start_x + 4; |
54 | | |
55 | 20.6M | for (int j = start_y; j < end_y; j++) { |
56 | 82.6M | for (int k = start_x; k < end_x; k++) { |
57 | 66.1M | if (mask & 0x8000) { |
58 | 2.02M | if (j >= avctx->height || k >= avctx->width) { |
59 | 1.25M | mask = mask << 1; |
60 | 1.25M | continue; |
61 | 1.25M | } |
62 | 768k | AV_WB24(&frame->data[0][frame->linesize[0] * (h - j) + 3 * k], color); |
63 | 768k | pixels_overwritten ++; |
64 | 768k | } |
65 | 64.9M | mask = mask << 1; |
66 | 64.9M | } |
67 | 16.5M | } |
68 | 4.13M | } |
69 | 17.1k | return pixels_overwritten; |
70 | 40.3k | } |
71 | | |
72 | | static int fill_tileX(AVCodecContext *avctx, int tile_width, int tile_height, |
73 | | int color, AVFrame *frame) |
74 | 130k | { |
75 | 130k | ARBCContext *s = avctx->priv_data; |
76 | 130k | GetByteContext *gb = &s->gb; |
77 | 130k | const int step_h = tile_height / 4; |
78 | 130k | const int step_w = tile_width / 4; |
79 | 130k | int nb_tiles = bytestream2_get_le16(gb); |
80 | 130k | int h = avctx->height - 1; |
81 | 130k | int pixels_overwritten = 0; |
82 | | |
83 | 130k | if ((avctx->width / tile_width + 1) * (avctx->height / tile_height + 1) < nb_tiles) |
84 | 104k | return 0; |
85 | | |
86 | 1.76M | for (int i = 0; i < nb_tiles; i++) { |
87 | 1.73M | int y = bytestream2_get_byte(gb); |
88 | 1.73M | int x = bytestream2_get_byte(gb); |
89 | 1.73M | uint16_t mask = bytestream2_get_le16(gb); |
90 | 1.73M | int start_y = y * tile_height, start_x = x * tile_width; |
91 | 1.73M | int end_y = start_y + tile_height, end_x = start_x + tile_width; |
92 | | |
93 | 1.73M | if (start_x >= avctx->width || start_y >= avctx->height) |
94 | 42.3k | continue; |
95 | | |
96 | 8.47M | for (int j = start_y; j < end_y; j += step_h) { |
97 | 33.8M | for (int k = start_x; k < end_x; k += step_w) { |
98 | 27.1M | if (mask & 0x8000U) { |
99 | 5.16M | for (int m = 0; m < step_h; m++) { |
100 | 1.11G | for (int n = 0; n < step_w; n++) { |
101 | 1.11G | if (j + m >= avctx->height || k + n >= avctx->width) |
102 | 1.11G | continue; |
103 | 3.95M | AV_WB24(&frame->data[0][frame->linesize[0] * (h - (j + m)) + 3 * (k + n)], color); |
104 | 3.95M | } |
105 | 5.05M | } |
106 | 104k | pixels_overwritten += FFMIN(step_h, avctx->height - j) * FFMIN(step_w, avctx->width - k); |
107 | 104k | } |
108 | 27.1M | mask = mask << 1; |
109 | 27.1M | } |
110 | 6.77M | } |
111 | 1.69M | } |
112 | 25.8k | return pixels_overwritten; |
113 | 130k | } |
114 | | |
115 | | static int decode_frame(AVCodecContext *avctx, AVFrame *frame, |
116 | | int *got_frame, AVPacket *avpkt) |
117 | 145k | { |
118 | 145k | ARBCContext *s = avctx->priv_data; |
119 | 145k | int ret, nb_segments; |
120 | 145k | int prev_pixels = avctx->width * avctx->height; |
121 | | |
122 | 145k | if (avpkt->size < 10) |
123 | 6.41k | return AVERROR_INVALIDDATA; |
124 | | |
125 | 139k | bytestream2_init(&s->gb, avpkt->data, avpkt->size); |
126 | 139k | bytestream2_skip(&s->gb, 8); |
127 | 139k | nb_segments = bytestream2_get_le16(&s->gb); |
128 | 139k | if (nb_segments == 0) |
129 | 131k | return avpkt->size; |
130 | | |
131 | 8.36k | if (7 * nb_segments > bytestream2_get_bytes_left(&s->gb)) |
132 | 1.69k | return AVERROR_INVALIDDATA; |
133 | | |
134 | 6.66k | if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) |
135 | 791 | return ret; |
136 | | |
137 | 5.87k | if (s->prev_frame->data[0]) { |
138 | 3.17k | ret = av_frame_copy(frame, s->prev_frame); |
139 | 3.17k | if (ret < 0) |
140 | 0 | return ret; |
141 | 3.17k | } |
142 | | |
143 | 179k | for (int i = 0; i < nb_segments; i++) { |
144 | 174k | int resolution_flag; |
145 | 174k | int fill; |
146 | | |
147 | 174k | if (bytestream2_get_bytes_left(&s->gb) <= 0) |
148 | 686 | return AVERROR_INVALIDDATA; |
149 | | |
150 | 174k | fill = bytestream2_get_byte(&s->gb) << 16; |
151 | 174k | bytestream2_skip(&s->gb, 1); |
152 | 174k | fill |= bytestream2_get_byte(&s->gb) << 8; |
153 | 174k | bytestream2_skip(&s->gb, 1); |
154 | 174k | fill |= bytestream2_get_byte(&s->gb) << 0; |
155 | 174k | bytestream2_skip(&s->gb, 1); |
156 | 174k | resolution_flag = bytestream2_get_byte(&s->gb); |
157 | | |
158 | 174k | if (resolution_flag & 0x10) |
159 | 31.2k | prev_pixels -= fill_tileX(avctx, 1024, 1024, fill, frame); |
160 | 174k | if (resolution_flag & 0x08) |
161 | 28.8k | prev_pixels -= fill_tileX(avctx, 256, 256, fill, frame); |
162 | 174k | if (resolution_flag & 0x04) |
163 | 36.7k | prev_pixels -= fill_tileX(avctx, 64, 64, fill, frame); |
164 | 174k | if (resolution_flag & 0x02) |
165 | 33.9k | prev_pixels -= fill_tileX(avctx, 16, 16, fill, frame); |
166 | 174k | if (resolution_flag & 0x01) |
167 | 40.3k | prev_pixels -= fill_tile4(avctx, fill, frame); |
168 | 174k | } |
169 | | |
170 | 5.19k | if ((ret = av_frame_replace(s->prev_frame, frame)) < 0) |
171 | 0 | return ret; |
172 | | |
173 | 5.19k | frame->pict_type = prev_pixels <= 0 ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; |
174 | 5.19k | if (prev_pixels <= 0) |
175 | 256 | frame->flags |= AV_FRAME_FLAG_KEY; |
176 | 4.93k | else |
177 | 4.93k | frame->flags &= ~AV_FRAME_FLAG_KEY; |
178 | 5.19k | *got_frame = 1; |
179 | | |
180 | 5.19k | return avpkt->size; |
181 | 5.19k | } |
182 | | |
183 | | static av_cold int decode_init(AVCodecContext *avctx) |
184 | 898 | { |
185 | 898 | ARBCContext *s = avctx->priv_data; |
186 | | |
187 | 898 | avctx->pix_fmt = AV_PIX_FMT_RGB24; |
188 | | |
189 | 898 | s->prev_frame = av_frame_alloc(); |
190 | 898 | if (!s->prev_frame) |
191 | 0 | return AVERROR(ENOMEM); |
192 | | |
193 | 898 | return 0; |
194 | 898 | } |
195 | | |
196 | | static av_cold void decode_flush(AVCodecContext *avctx) |
197 | 25.0k | { |
198 | 25.0k | ARBCContext *s = avctx->priv_data; |
199 | | |
200 | 25.0k | av_frame_unref(s->prev_frame); |
201 | 25.0k | } |
202 | | |
203 | | static av_cold int decode_close(AVCodecContext *avctx) |
204 | 898 | { |
205 | 898 | ARBCContext *s = avctx->priv_data; |
206 | | |
207 | 898 | av_frame_free(&s->prev_frame); |
208 | | |
209 | 898 | return 0; |
210 | 898 | } |
211 | | |
212 | | const FFCodec ff_arbc_decoder = { |
213 | | .p.name = "arbc", |
214 | | CODEC_LONG_NAME("Gryphon's Anim Compressor"), |
215 | | .p.type = AVMEDIA_TYPE_VIDEO, |
216 | | .p.id = AV_CODEC_ID_ARBC, |
217 | | .priv_data_size = sizeof(ARBCContext), |
218 | | .init = decode_init, |
219 | | FF_CODEC_DECODE_CB(decode_frame), |
220 | | .flush = decode_flush, |
221 | | .close = decode_close, |
222 | | .p.capabilities = AV_CODEC_CAP_DR1, |
223 | | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, |
224 | | }; |