FFmpeg
Loading...
Searching...
No Matches
brenderpix.c
Go to the documentation of this file.
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#define HEADER1_CHUNK 0x03
32#define HEADER2_CHUNK 0x3D
33#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 */
45static 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
108typedef struct PixHeader {
109 int width;
112} PixHeader;
113
115{
116 unsigned int header_len = bytestream2_get_be32(pgb);
117
118 out->format = bytestream2_get_byte(pgb);
119 bytestream2_skip(pgb, 2);
120 out->width = bytestream2_get_be16(pgb);
121 out->height = bytestream2_get_be16(pgb);
122
123 // the header is at least 11 bytes long; we read the first 7
124 if (header_len < 11)
125 return AVERROR_INVALIDDATA;
126
127 // skip the rest of the header
128 bytestream2_skip(pgb, header_len - 7);
129
130 return 0;
131}
132
134 int *got_frame, AVPacket *avpkt)
135{
136 int ret, i;
138
139 unsigned int bytes_pp;
140 unsigned int magic[4];
141 unsigned int chunk_type;
142 unsigned int data_len;
143 unsigned int bytes_per_scanline;
144 unsigned int bytes_left;
145 PixHeader hdr;
146
147 bytestream2_init(&gb, avpkt->data, avpkt->size);
148
149 magic[0] = bytestream2_get_be32(&gb);
150 magic[1] = bytestream2_get_be32(&gb);
151 magic[2] = bytestream2_get_be32(&gb);
152 magic[3] = bytestream2_get_be32(&gb);
153
154 if (magic[0] != 0x12 ||
155 magic[1] != 0x08 ||
156 magic[2] != 0x02 ||
157 magic[3] != 0x02) {
158 av_log(avctx, AV_LOG_ERROR, "Not a BRender PIX file.\n");
159 return AVERROR_INVALIDDATA;
160 }
161
162 chunk_type = bytestream2_get_be32(&gb);
163 if (chunk_type != HEADER1_CHUNK && chunk_type != HEADER2_CHUNK) {
164 av_log(avctx, AV_LOG_ERROR, "Invalid chunk type %d.\n", chunk_type);
165 return AVERROR_INVALIDDATA;
166 }
167
168 ret = pix_decode_header(&hdr, &gb);
169 if (ret < 0) {
170 av_log(avctx, AV_LOG_ERROR, "Invalid header length.\n");
171 return ret;
172 }
173 switch (hdr.format) {
174 case 3:
175 avctx->pix_fmt = AV_PIX_FMT_PAL8;
176 bytes_pp = 1;
177 break;
178 case 4:
180 bytes_pp = 2;
181 break;
182 case 5:
184 bytes_pp = 2;
185 break;
186 case 6:
187 avctx->pix_fmt = AV_PIX_FMT_RGB24;
188 bytes_pp = 3;
189 break;
190 case 7:
191 avctx->pix_fmt = AV_PIX_FMT_0RGB;
192 bytes_pp = 4;
193 break;
194 case 8: // ARGB
195 avctx->pix_fmt = AV_PIX_FMT_ARGB;
196 bytes_pp = 4;
197 break;
198 case 18:
199 avctx->pix_fmt = AV_PIX_FMT_YA8;
200 bytes_pp = 2;
201 break;
202 default:
203 avpriv_request_sample(avctx, "Format %d", hdr.format);
205 }
206 bytes_per_scanline = bytes_pp * hdr.width;
207
208 if (bytestream2_get_bytes_left(&gb) < hdr.height * bytes_per_scanline)
209 return AVERROR_INVALIDDATA;
210
211 if ((ret = ff_set_dimensions(avctx, hdr.width, hdr.height)) < 0)
212 return ret;
213
214 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
215 return ret;
216
217 chunk_type = bytestream2_get_be32(&gb);
218
219 if (avctx->pix_fmt == AV_PIX_FMT_PAL8 &&
220 (chunk_type == HEADER1_CHUNK ||
221 chunk_type == HEADER2_CHUNK)) {
222 /* read palette data from data[1] */
223 PixHeader palhdr;
224 uint32_t *pal_out = (uint32_t *)frame->data[1];
225
226 ret = pix_decode_header(&palhdr, &gb);
227 if (ret < 0) {
228 av_log(avctx, AV_LOG_ERROR, "Invalid palette header length.\n");
229 return ret;
230 }
231 if (palhdr.format != 7)
232 avpriv_request_sample(avctx, "Palette not in RGB format");
233
234 chunk_type = bytestream2_get_be32(&gb);
235 data_len = bytestream2_get_be32(&gb);
236 bytestream2_skip(&gb, 8);
237 if (chunk_type != IMAGE_DATA_CHUNK || data_len != 1032 ||
238 bytestream2_get_bytes_left(&gb) < 1032) {
239 av_log(avctx, AV_LOG_ERROR, "Invalid palette data.\n");
240 return AVERROR_INVALIDDATA;
241 }
242 // palette data is surrounded by 8 null bytes (both top and bottom)
243 // convert 0RGB to machine endian format (ARGB32)
244 for (i = 0; i < 256; ++i)
245 *pal_out++ = (0xFFU << 24) | bytestream2_get_be32u(&gb);
246 bytestream2_skip(&gb, 8);
247
248 chunk_type = bytestream2_get_be32(&gb);
249 } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
250 /* no palette supplied, use the default one */
251 uint32_t *pal_out = (uint32_t *)frame->data[1];
252
253 // TODO: add an AVOption to load custom palette files
254 av_log(avctx, AV_LOG_WARNING,
255 "Using default palette, colors might be off.\n");
256 memcpy(pal_out, std_pal_table, sizeof(uint32_t) * 256);
257 }
258
259 data_len = bytestream2_get_be32(&gb);
260 bytestream2_skip(&gb, 8);
261
262 // read the image data to the buffer
263 bytes_left = bytestream2_get_bytes_left(&gb);
264
265 if (chunk_type != IMAGE_DATA_CHUNK || data_len != bytes_left ||
266 bytes_left / bytes_per_scanline < hdr.height) {
267 av_log(avctx, AV_LOG_ERROR, "Invalid image data.\n");
268 return AVERROR_INVALIDDATA;
269 }
270
271 av_image_copy_plane(frame->data[0], frame->linesize[0],
272 avpkt->data + bytestream2_tell(&gb),
273 bytes_per_scanline,
274 bytes_per_scanline, hdr.height);
275
276 *got_frame = 1;
277
278 return avpkt->size;
279}
280
282 .p.name = "brender_pix",
283 CODEC_LONG_NAME("BRender PIX image"),
284 .p.type = AVMEDIA_TYPE_VIDEO,
286 .p.capabilities = AV_CODEC_CAP_DR1,
288};
const FFCodec ff_brender_pix_decoder
Definition brenderpix.c:281
Libavcodec external API header.
#define HEADER2_CHUNK
Definition brenderpix.c:32
static int pix_decode_header(PixHeader *out, GetByteContext *pgb)
Definition brenderpix.c:114
#define HEADER1_CHUNK
Definition brenderpix.c:31
static const uint32_t std_pal_table[256]
Definition brenderpix.c:45
#define IMAGE_DATA_CHUNK
Definition brenderpix.c:33
static int pix_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt)
Definition brenderpix.c:133
static av_always_inline int bytestream2_get_bytes_left(const GetByteContext *g)
Definition bytestream.h:158
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition bytestream.h:137
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition bytestream.h:168
static av_always_inline int bytestream2_tell(const GetByteContext *g)
Definition bytestream.h:192
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define FF_CODEC_DECODE_CB(func)
#define CODEC_LONG_NAME(str)
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition decode.c:1777
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Definition utils.c:91
static AVFrame * frame
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition codec.h:49
@ AV_CODEC_ID_BRENDER_PIX
Definition codec_id.h:227
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition error.h:64
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
void av_image_copy_plane(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize, int bytewidth, int height)
Copy image plane from src to dst.
Definition imgutils.c:374
misc image utilities
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition pixfmt.h:75
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition pixfmt.h:99
@ AV_PIX_FMT_RGB555BE
packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), big-endian , X=unused/undefined
Definition pixfmt.h:114
@ AV_PIX_FMT_RGB565BE
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian
Definition pixfmt.h:112
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition pixfmt.h:84
@ AV_PIX_FMT_YA8
8 bits gray, 8 bits alpha
Definition pixfmt.h:140
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Definition pixfmt.h:262
main external API structure.
Definition avcodec.h:443
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition avcodec.h:643
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
This structure stores compressed data.
Definition packet.h:580
int size
Definition packet.h:604
uint8_t * data
Definition packet.h:603
#define avpriv_request_sample(...)
#define av_log(a,...)
static FILE * out
Definition movenc.c:55