FFmpeg
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 "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 
114 {
115  unsigned int header_len = bytestream2_get_be32(pgb);
116 
117  out->format = bytestream2_get_byte(pgb);
118  bytestream2_skip(pgb, 2);
119  out->width = bytestream2_get_be16(pgb);
120  out->height = bytestream2_get_be16(pgb);
121 
122  // the header is at least 11 bytes long; we read the first 7
123  if (header_len < 11)
124  return AVERROR_INVALIDDATA;
125 
126  // skip the rest of the header
127  bytestream2_skip(pgb, header_len - 7);
128 
129  return 0;
130 }
131 
132 static int pix_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
133  AVPacket *avpkt)
134 {
135  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  bytestream2_init(&gb, avpkt->data, avpkt->size);
149 
150  magic[0] = bytestream2_get_be32(&gb);
151  magic[1] = bytestream2_get_be32(&gb);
152  magic[2] = bytestream2_get_be32(&gb);
153  magic[3] = bytestream2_get_be32(&gb);
154 
155  if (magic[0] != 0x12 ||
156  magic[1] != 0x08 ||
157  magic[2] != 0x02 ||
158  magic[3] != 0x02) {
159  av_log(avctx, AV_LOG_ERROR, "Not a BRender PIX file.\n");
160  return AVERROR_INVALIDDATA;
161  }
162 
163  chunk_type = bytestream2_get_be32(&gb);
164  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  ret = pix_decode_header(&hdr, &gb);
170  if (ret < 0) {
171  av_log(avctx, AV_LOG_ERROR, "Invalid header length.\n");
172  return ret;
173  }
174  switch (hdr.format) {
175  case 3:
176  avctx->pix_fmt = AV_PIX_FMT_PAL8;
177  bytes_pp = 1;
178  break;
179  case 4:
180  avctx->pix_fmt = AV_PIX_FMT_RGB555BE;
181  bytes_pp = 2;
182  break;
183  case 5:
184  avctx->pix_fmt = AV_PIX_FMT_RGB565BE;
185  bytes_pp = 2;
186  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  case 18:
200  avctx->pix_fmt = AV_PIX_FMT_YA8;
201  bytes_pp = 2;
202  break;
203  default:
204  avpriv_request_sample(avctx, "Format %d", hdr.format);
205  return AVERROR_PATCHWELCOME;
206  }
207  bytes_per_scanline = bytes_pp * hdr.width;
208 
209  if (bytestream2_get_bytes_left(&gb) < hdr.height * bytes_per_scanline)
210  return AVERROR_INVALIDDATA;
211 
212  if ((ret = ff_set_dimensions(avctx, hdr.width, hdr.height)) < 0)
213  return ret;
214 
215  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
216  return ret;
217 
218  chunk_type = bytestream2_get_be32(&gb);
219 
220  if (avctx->pix_fmt == AV_PIX_FMT_PAL8 &&
221  (chunk_type == HEADER1_CHUNK ||
222  chunk_type == HEADER2_CHUNK)) {
223  /* read palette data from data[1] */
224  PixHeader palhdr;
225  uint32_t *pal_out = (uint32_t *)frame->data[1];
226 
227  ret = pix_decode_header(&palhdr, &gb);
228  if (ret < 0) {
229  av_log(avctx, AV_LOG_ERROR, "Invalid palette header length.\n");
230  return ret;
231  }
232  if (palhdr.format != 7)
233  avpriv_request_sample(avctx, "Palette not in RGB format");
234 
235  chunk_type = bytestream2_get_be32(&gb);
236  data_len = bytestream2_get_be32(&gb);
237  bytestream2_skip(&gb, 8);
238  if (chunk_type != IMAGE_DATA_CHUNK || data_len != 1032 ||
239  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  for (i = 0; i < 256; ++i)
246  *pal_out++ = (0xFFU << 24) | bytestream2_get_be32u(&gb);
247  bytestream2_skip(&gb, 8);
248 
249  frame->palette_has_changed = 1;
250 
251  chunk_type = bytestream2_get_be32(&gb);
252  } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
253  /* no palette supplied, use the default one */
254  uint32_t *pal_out = (uint32_t *)frame->data[1];
255 
256  // TODO: add an AVOption to load custom palette files
257  av_log(avctx, AV_LOG_WARNING,
258  "Using default palette, colors might be off.\n");
259  memcpy(pal_out, std_pal_table, sizeof(uint32_t) * 256);
260 
261  frame->palette_has_changed = 1;
262  }
263 
264  data_len = bytestream2_get_be32(&gb);
265  bytestream2_skip(&gb, 8);
266 
267  // read the image data to the buffer
268  bytes_left = bytestream2_get_bytes_left(&gb);
269 
270  if (chunk_type != IMAGE_DATA_CHUNK || data_len != bytes_left ||
271  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  av_image_copy_plane(frame->data[0], frame->linesize[0],
277  avpkt->data + bytestream2_tell(&gb),
278  bytes_per_scanline,
279  bytes_per_scanline, hdr.height);
280 
281  frame->pict_type = AV_PICTURE_TYPE_I;
282  frame->key_frame = 1;
283  *got_frame = 1;
284 
285  return avpkt->size;
286 }
287 
289  .name = "brender_pix",
290  .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"),
291  .type = AVMEDIA_TYPE_VIDEO,
293  .decode = pix_decode_frame,
294  .capabilities = AV_CODEC_CAP_DR1,
295 };
AVCodec
AVCodec.
Definition: avcodec.h:3481
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
pix_decode_header
static int pix_decode_header(PixHeader *out, GetByteContext *pgb)
Definition: brenderpix.c:113
AV_PIX_FMT_YA8
@ AV_PIX_FMT_YA8
8 bits gray, 8 bits alpha
Definition: pixfmt.h:143
out
FILE * out
Definition: movenc.c:54
GetByteContext
Definition: bytestream.h:33
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
internal.h
AVPacket::data
uint8_t * data
Definition: avcodec.h:1477
data
const char data[16]
Definition: mxf.c:91
AV_PIX_FMT_RGB555BE
@ AV_PIX_FMT_RGB555BE
packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), big-endian , X=unused/undefined
Definition: pixfmt.h:107
bytestream2_get_bytes_left
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:154
av_image_copy_plane
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:338
IMAGE_DATA_CHUNK
#define IMAGE_DATA_CHUNK
Definition: brenderpix.c:32
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:164
HEADER2_CHUNK
#define HEADER2_CHUNK
Definition: brenderpix.c:31
ff_brender_pix_decoder
AVCodec ff_brender_pix_decoder
Definition: brenderpix.c:288
PixHeader::format
int format
Definition: brenderpix.c:110
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
pix_decode_frame
static int pix_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: brenderpix.c:132
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:274
PixHeader::width
int width
Definition: brenderpix.c:108
std_pal_table
static const uint32_t std_pal_table[256]
Definition: brenderpix.c:44
bytestream2_tell
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:188
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1965
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:981
AVPacket::size
int size
Definition: avcodec.h:1478
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:188
AV_PIX_FMT_ARGB
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:92
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
AVCodec::name
const char * name
Name of the codec implementation.
Definition: avcodec.h:3488
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1775
avcodec.h
AV_PIX_FMT_PAL8
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
ret
ret
Definition: filter_design.txt:187
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
AVCodecContext
main external API structure.
Definition: avcodec.h:1565
PixHeader
Definition: brenderpix.c:107
AV_PIX_FMT_RGB565BE
@ AV_PIX_FMT_RGB565BE
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian
Definition: pixfmt.h:105
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
ff_set_dimensions
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Check that the provided frame dimensions are valid and set them on the codec context.
Definition: utils.c:104
avpriv_request_sample
#define avpriv_request_sample(...)
Definition: tableprint_vlc.h:39
AVPacket
This structure stores compressed data.
Definition: avcodec.h:1454
PixHeader::height
int height
Definition: brenderpix.c:109
HEADER1_CHUNK
#define HEADER1_CHUNK
Definition: brenderpix.c:30
bytestream.h
imgutils.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
AV_PIX_FMT_0RGB
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Definition: pixfmt.h:237
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
AV_CODEC_ID_BRENDER_PIX
@ AV_CODEC_ID_BRENDER_PIX
Definition: avcodec.h:396
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59