FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/brenderpix.c
Date: 2021-09-26 18:22:30
Exec Total Coverage
Lines: 75 111 67.6%
Branches: 32 56 57.1%

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