/src/ffmpeg/libavcodec/brenderpix.c
Line | Count | Source |
1 | | /* |
2 | | * BRender PIX (.pix) image decoder |
3 | | * Copyright (c) 2012 Aleksi Nurmi |
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 | | /* Tested against samples from I-War / Independence War and Defiance. */ |
23 | | |
24 | | #include "libavutil/imgutils.h" |
25 | | |
26 | | #include "avcodec.h" |
27 | | #include "bytestream.h" |
28 | | #include "codec_internal.h" |
29 | | #include "decode.h" |
30 | | |
31 | 455k | #define HEADER1_CHUNK 0x03 |
32 | 107k | #define HEADER2_CHUNK 0x3D |
33 | 230k | #define IMAGE_DATA_CHUNK 0x21 |
34 | | |
35 | | /* In 8-bit colour mode, 256 colours are available at any time. Which 256 |
36 | | * colours are available is determined by the contents of the hardware palette |
37 | | * (or CLUT). In this case, the palette supplied with BRender (std.pal) has |
38 | | * been loaded into the CLUT. |
39 | | * |
40 | | * The 256 colours in std.pal are divided into seven ranges, or `colour ramps'. |
41 | | * The first 64 colours represent shades of grey ranging from very dark grey |
42 | | * (black) to very light grey (white). The following colours are 32-element |
43 | | * ramps for six colours as shown below. |
44 | | */ |
45 | | static const uint32_t std_pal_table[256] = { |
46 | | // gray |
47 | | 0xFF000000, 0xFF030303, 0xFF060606, 0xFF090909, 0xFF0C0C0C, 0xFF0F0F0F, |
48 | | 0xFF121212, 0xFF151515, 0xFF181818, 0xFF1B1B1B, 0xFF1E1E1E, 0xFF212121, |
49 | | 0xFF242424, 0xFF272727, 0xFF2A2A2A, 0xFF2D2D2D, 0xFF313131, 0xFF343434, |
50 | | 0xFF373737, 0xFF3A3A3A, 0xFF3D3D3D, 0xFF404040, 0xFF434343, 0xFF464646, |
51 | | 0xFF494949, 0xFF4C4C4C, 0xFF4F4F4F, 0xFF525252, 0xFF555555, 0xFF585858, |
52 | | 0xFF5B5B5B, 0xFF5E5E5E, 0xFF626262, 0xFF656565, 0xFF686868, 0xFF6B6B6B, |
53 | | 0xFF6E6E6E, 0xFF717171, 0xFF747474, 0xFF777777, 0xFF7A7A7A, 0xFF7D7D7D, |
54 | | 0xFF808080, 0xFF838383, 0xFF868686, 0xFF898989, 0xFF8C8C8C, 0xFF8F8F8F, |
55 | | 0xFF939393, 0xFF999999, 0xFFA0A0A0, 0xFFA7A7A7, 0xFFAEAEAE, 0xFFB4B4B4, |
56 | | 0xFFBBBBBB, 0xFFC2C2C2, 0xFFC9C9C9, 0xFFCFCFCF, 0xFFD6D6D6, 0xFFDDDDDD, |
57 | | 0xFFE4E4E4, 0xFFEAEAEA, 0xFFF1F1F1, 0xFFF8F8F8, |
58 | | |
59 | | // blue |
60 | | 0xFF000000, 0xFF020209, 0xFF050513, 0xFF07071D, 0xFF0A0A27, 0xFF0C0C31, |
61 | | 0xFF0F0F3B, 0xFF111145, 0xFF14144F, 0xFF161659, 0xFF181863, 0xFF1B1B6D, |
62 | | 0xFF1E1E77, 0xFF202080, 0xFF22228A, 0xFF252594, 0xFF28289E, 0xFF2A2AA8, |
63 | | 0xFF2D2DB2, 0xFF2F2FBC, 0xFF3131C6, 0xFF3434D0, 0xFF3737DA, 0xFF3939E4, |
64 | | 0xFF3C3CEE, 0xFF5454F0, 0xFF6C6CF2, 0xFF8585F4, 0xFF9D9DF6, 0xFFB5B5F8, |
65 | | 0xFFCECEFA, 0xFFE6E6FC, |
66 | | |
67 | | // green |
68 | | 0xFF000000, 0xFF020902, 0xFF051305, 0xFF071D07, 0xFF0A270A, 0xFF0C310C, |
69 | | 0xFF0F3B0F, 0xFF114511, 0xFF144F14, 0xFF165916, 0xFF186318, 0xFF1B6D1B, |
70 | | 0xFF1E771E, 0xFF208020, 0xFF228A22, 0xFF259425, 0xFF289E28, 0xFF2AA82A, |
71 | | 0xFF2DB22D, 0xFF2FBC2F, 0xFF31C631, 0xFF34D034, 0xFF37DA37, 0xFF39E439, |
72 | | 0xFF3CEE3C, 0xFF54F054, 0xFF6CF26C, 0xFF85F485, 0xFF9DF69D, 0xFFB5F8B5, |
73 | | 0xFFCEFACE, 0xFFE6FCE6, |
74 | | |
75 | | // cyan |
76 | | 0xFF000000, 0xFF020909, 0xFF051313, 0xFF071D1D, 0xFF0A2727, 0xFF0C3131, |
77 | | 0xFF0F3B3B, 0xFF114545, 0xFF144F4F, 0xFF165959, 0xFF186363, 0xFF1B6D6D, |
78 | | 0xFF1E7777, 0xFF208080, 0xFF228A8A, 0xFF259494, 0xFF289E9E, 0xFF2AA8A8, |
79 | | 0xFF2DB2B2, 0xFF2FBCBC, 0xFF31C6C6, 0xFF34D0D0, 0xFF37DADA, 0xFF39E4E4, |
80 | | 0xFF3CEEEE, 0xFF54F0F0, 0xFF6CF2F2, 0xFF85F4F4, 0xFF9DF6F6, 0xFFB5F8F8, |
81 | | 0xFFCEFAFA, 0xFFE6FCFC, |
82 | | |
83 | | // red |
84 | | 0xFF000000, 0xFF090202, 0xFF130505, 0xFF1D0707, 0xFF270A0A, 0xFF310C0C, |
85 | | 0xFF3B0F0F, 0xFF451111, 0xFF4F1414, 0xFF591616, 0xFF631818, 0xFF6D1B1B, |
86 | | 0xFF771E1E, 0xFF802020, 0xFF8A2222, 0xFF942525, 0xFF9E2828, 0xFFA82A2A, |
87 | | 0xFFB22D2D, 0xFFBC2F2F, 0xFFC63131, 0xFFD03434, 0xFFDA3737, 0xFFE43939, |
88 | | 0xFFEE3C3C, 0xFFF05454, 0xFFF26C6C, 0xFFF48585, 0xFFF69D9D, 0xFFF8B5B5, |
89 | | 0xFFFACECE, 0xFFFCE6E6, |
90 | | |
91 | | // magenta |
92 | | 0xFF000000, 0xFF090209, 0xFF130513, 0xFF1D071D, 0xFF270A27, 0xFF310C31, |
93 | | 0xFF3B0F3B, 0xFF451145, 0xFF4F144F, 0xFF591659, 0xFF631863, 0xFF6D1B6D, |
94 | | 0xFF771E77, 0xFF802080, 0xFF8A228A, 0xFF942594, 0xFF9E289E, 0xFFA82AA8, |
95 | | 0xFFB22DB2, 0xFFBC2FBC, 0xFFC631C6, 0xFFD034D0, 0xFFDA37DA, 0xFFE439E4, |
96 | | 0xFFEE3CEE, 0xFFF054F0, 0xFFF26CF2, 0xFFF485F4, 0xFFF69DF6, 0xFFF8B5F8, |
97 | | 0xFFFACEFA, 0xFFFCE6FC, |
98 | | |
99 | | // yellow |
100 | | 0xFF000000, 0xFF090902, 0xFF131305, 0xFF1D1D07, 0xFF27270A, 0xFF31310C, |
101 | | 0xFF3B3B0F, 0xFF454511, 0xFF4F4F14, 0xFF595916, 0xFF636318, 0xFF6D6D1B, |
102 | | 0xFF77771E, 0xFF808020, 0xFF8A8A22, 0xFF949425, 0xFF9E9E28, 0xFFA8A82A, |
103 | | 0xFFB2B22D, 0xFFBCBC2F, 0xFFC6C631, 0xFFD0D034, 0xFFDADA37, 0xFFE4E439, |
104 | | 0xFFEEEE3C, 0xFFF0F054, 0xFFF2F26C, 0xFFF4F485, 0xFFF6F69D, 0xFFF8F8B5, |
105 | | 0xFFFAFACE, 0xFFFCFCE6, |
106 | | }; |
107 | | |
108 | | typedef struct PixHeader { |
109 | | int width; |
110 | | int height; |
111 | | int format; |
112 | | } PixHeader; |
113 | | |
114 | | static int pix_decode_header(PixHeader *out, GetByteContext *pgb) |
115 | 121k | { |
116 | 121k | unsigned int header_len = bytestream2_get_be32(pgb); |
117 | | |
118 | 121k | out->format = bytestream2_get_byte(pgb); |
119 | 121k | bytestream2_skip(pgb, 2); |
120 | 121k | out->width = bytestream2_get_be16(pgb); |
121 | 121k | out->height = bytestream2_get_be16(pgb); |
122 | | |
123 | | // the header is at least 11 bytes long; we read the first 7 |
124 | 121k | if (header_len < 11) |
125 | 845 | return AVERROR_INVALIDDATA; |
126 | | |
127 | | // skip the rest of the header |
128 | 120k | bytestream2_skip(pgb, header_len - 7); |
129 | | |
130 | 120k | return 0; |
131 | 121k | } |
132 | | |
133 | | static int pix_decode_frame(AVCodecContext *avctx, AVFrame *frame, |
134 | | int *got_frame, AVPacket *avpkt) |
135 | 229k | { |
136 | 229k | int ret, i; |
137 | 229k | GetByteContext gb; |
138 | | |
139 | 229k | unsigned int bytes_pp; |
140 | 229k | unsigned int magic[4]; |
141 | 229k | unsigned int chunk_type; |
142 | 229k | unsigned int data_len; |
143 | 229k | unsigned int bytes_per_scanline; |
144 | 229k | unsigned int bytes_left; |
145 | 229k | PixHeader hdr; |
146 | | |
147 | 229k | bytestream2_init(&gb, avpkt->data, avpkt->size); |
148 | | |
149 | 229k | magic[0] = bytestream2_get_be32(&gb); |
150 | 229k | magic[1] = bytestream2_get_be32(&gb); |
151 | 229k | magic[2] = bytestream2_get_be32(&gb); |
152 | 229k | magic[3] = bytestream2_get_be32(&gb); |
153 | | |
154 | 229k | if (magic[0] != 0x12 || |
155 | 118k | magic[1] != 0x08 || |
156 | 117k | magic[2] != 0x02 || |
157 | 117k | magic[3] != 0x02) { |
158 | 112k | av_log(avctx, AV_LOG_ERROR, "Not a BRender PIX file.\n"); |
159 | 112k | return AVERROR_INVALIDDATA; |
160 | 112k | } |
161 | | |
162 | 116k | chunk_type = bytestream2_get_be32(&gb); |
163 | 116k | if (chunk_type != HEADER1_CHUNK && chunk_type != HEADER2_CHUNK) { |
164 | 493 | av_log(avctx, AV_LOG_ERROR, "Invalid chunk type %d.\n", chunk_type); |
165 | 493 | return AVERROR_INVALIDDATA; |
166 | 493 | } |
167 | | |
168 | 116k | ret = pix_decode_header(&hdr, &gb); |
169 | 116k | if (ret < 0) { |
170 | 445 | av_log(avctx, AV_LOG_ERROR, "Invalid header length.\n"); |
171 | 445 | return ret; |
172 | 445 | } |
173 | 115k | switch (hdr.format) { |
174 | 112k | case 3: |
175 | 112k | avctx->pix_fmt = AV_PIX_FMT_PAL8; |
176 | 112k | bytes_pp = 1; |
177 | 112k | break; |
178 | 695 | case 4: |
179 | 695 | avctx->pix_fmt = AV_PIX_FMT_RGB555BE; |
180 | 695 | bytes_pp = 2; |
181 | 695 | break; |
182 | 1.17k | case 5: |
183 | 1.17k | avctx->pix_fmt = AV_PIX_FMT_RGB565BE; |
184 | 1.17k | bytes_pp = 2; |
185 | 1.17k | break; |
186 | 376 | case 6: |
187 | 376 | avctx->pix_fmt = AV_PIX_FMT_RGB24; |
188 | 376 | bytes_pp = 3; |
189 | 376 | break; |
190 | 13 | case 7: |
191 | 13 | avctx->pix_fmt = AV_PIX_FMT_0RGB; |
192 | 13 | bytes_pp = 4; |
193 | 13 | break; |
194 | 386 | case 8: // ARGB |
195 | 386 | avctx->pix_fmt = AV_PIX_FMT_ARGB; |
196 | 386 | bytes_pp = 4; |
197 | 386 | break; |
198 | 141 | case 18: |
199 | 141 | avctx->pix_fmt = AV_PIX_FMT_YA8; |
200 | 141 | bytes_pp = 2; |
201 | 141 | break; |
202 | 857 | default: |
203 | 857 | avpriv_request_sample(avctx, "Format %d", hdr.format); |
204 | 857 | return AVERROR_PATCHWELCOME; |
205 | 115k | } |
206 | 114k | bytes_per_scanline = bytes_pp * hdr.width; |
207 | | |
208 | 114k | if (bytestream2_get_bytes_left(&gb) < hdr.height * bytes_per_scanline) |
209 | 525 | return AVERROR_INVALIDDATA; |
210 | | |
211 | 114k | if ((ret = ff_set_dimensions(avctx, hdr.width, hdr.height)) < 0) |
212 | 1.38k | return ret; |
213 | | |
214 | 113k | if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) |
215 | 0 | return ret; |
216 | | |
217 | 113k | chunk_type = bytestream2_get_be32(&gb); |
218 | | |
219 | 113k | if (avctx->pix_fmt == AV_PIX_FMT_PAL8 && |
220 | 110k | (chunk_type == HEADER1_CHUNK || |
221 | 106k | chunk_type == HEADER2_CHUNK)) { |
222 | | /* read palette data from data[1] */ |
223 | 5.29k | PixHeader palhdr; |
224 | 5.29k | uint32_t *pal_out = (uint32_t *)frame->data[1]; |
225 | | |
226 | 5.29k | ret = pix_decode_header(&palhdr, &gb); |
227 | 5.29k | if (ret < 0) { |
228 | 400 | av_log(avctx, AV_LOG_ERROR, "Invalid palette header length.\n"); |
229 | 400 | return ret; |
230 | 400 | } |
231 | 4.89k | if (palhdr.format != 7) |
232 | 2.21k | avpriv_request_sample(avctx, "Palette not in RGB format"); |
233 | | |
234 | 4.89k | chunk_type = bytestream2_get_be32(&gb); |
235 | 4.89k | data_len = bytestream2_get_be32(&gb); |
236 | 4.89k | bytestream2_skip(&gb, 8); |
237 | 4.89k | if (chunk_type != IMAGE_DATA_CHUNK || data_len != 1032 || |
238 | 2.81k | bytestream2_get_bytes_left(&gb) < 1032) { |
239 | 2.39k | av_log(avctx, AV_LOG_ERROR, "Invalid palette data.\n"); |
240 | 2.39k | return AVERROR_INVALIDDATA; |
241 | 2.39k | } |
242 | | // palette data is surrounded by 8 null bytes (both top and bottom) |
243 | | // convert 0RGB to machine endian format (ARGB32) |
244 | 641k | for (i = 0; i < 256; ++i) |
245 | 639k | *pal_out++ = (0xFFU << 24) | bytestream2_get_be32u(&gb); |
246 | 2.49k | bytestream2_skip(&gb, 8); |
247 | | |
248 | 2.49k | chunk_type = bytestream2_get_be32(&gb); |
249 | 107k | } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { |
250 | | /* no palette supplied, use the default one */ |
251 | 105k | uint32_t *pal_out = (uint32_t *)frame->data[1]; |
252 | | |
253 | | // TODO: add an AVOption to load custom palette files |
254 | 105k | av_log(avctx, AV_LOG_WARNING, |
255 | 105k | "Using default palette, colors might be off.\n"); |
256 | 105k | memcpy(pal_out, std_pal_table, sizeof(uint32_t) * 256); |
257 | 105k | } |
258 | | |
259 | 110k | data_len = bytestream2_get_be32(&gb); |
260 | 110k | bytestream2_skip(&gb, 8); |
261 | | |
262 | | // read the image data to the buffer |
263 | 110k | bytes_left = bytestream2_get_bytes_left(&gb); |
264 | | |
265 | 110k | if (chunk_type != IMAGE_DATA_CHUNK || data_len != bytes_left || |
266 | 102k | bytes_left / bytes_per_scanline < hdr.height) { |
267 | 7.49k | av_log(avctx, AV_LOG_ERROR, "Invalid image data.\n"); |
268 | 7.49k | return AVERROR_INVALIDDATA; |
269 | 7.49k | } |
270 | | |
271 | 102k | av_image_copy_plane(frame->data[0], frame->linesize[0], |
272 | 102k | avpkt->data + bytestream2_tell(&gb), |
273 | 102k | bytes_per_scanline, |
274 | 102k | bytes_per_scanline, hdr.height); |
275 | | |
276 | 102k | *got_frame = 1; |
277 | | |
278 | 102k | return avpkt->size; |
279 | 110k | } |
280 | | |
281 | | const FFCodec ff_brender_pix_decoder = { |
282 | | .p.name = "brender_pix", |
283 | | CODEC_LONG_NAME("BRender PIX image"), |
284 | | .p.type = AVMEDIA_TYPE_VIDEO, |
285 | | .p.id = AV_CODEC_ID_BRENDER_PIX, |
286 | | .p.capabilities = AV_CODEC_CAP_DR1, |
287 | | FF_CODEC_DECODE_CB(pix_decode_frame), |
288 | | }; |