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 "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  */
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 
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;
137  GetByteContext gb;
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:
179  avctx->pix_fmt = AV_PIX_FMT_RGB555BE;
180  bytes_pp = 2;
181  break;
182  case 5:
183  avctx->pix_fmt = AV_PIX_FMT_RGB565BE;
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);
204  return AVERROR_PATCHWELCOME;
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 #if FF_API_PALETTE_HAS_CHANGED
252 #endif
253 
254  chunk_type = bytestream2_get_be32(&gb);
255  } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
256  /* no palette supplied, use the default one */
257  uint32_t *pal_out = (uint32_t *)frame->data[1];
258 
259  // TODO: add an AVOption to load custom palette files
260  av_log(avctx, AV_LOG_WARNING,
261  "Using default palette, colors might be off.\n");
262  memcpy(pal_out, std_pal_table, sizeof(uint32_t) * 256);
263 
264 #if FF_API_PALETTE_HAS_CHANGED
268 #endif
269  }
270 
271  data_len = bytestream2_get_be32(&gb);
272  bytestream2_skip(&gb, 8);
273 
274  // read the image data to the buffer
275  bytes_left = bytestream2_get_bytes_left(&gb);
276 
277  if (chunk_type != IMAGE_DATA_CHUNK || data_len != bytes_left ||
278  bytes_left / bytes_per_scanline < hdr.height) {
279  av_log(avctx, AV_LOG_ERROR, "Invalid image data.\n");
280  return AVERROR_INVALIDDATA;
281  }
282 
284  avpkt->data + bytestream2_tell(&gb),
285  bytes_per_scanline,
286  bytes_per_scanline, hdr.height);
287 
290  *got_frame = 1;
291 
292  return avpkt->size;
293 }
294 
296  .p.name = "brender_pix",
297  CODEC_LONG_NAME("BRender PIX image"),
298  .p.type = AVMEDIA_TYPE_VIDEO,
299  .p.id = AV_CODEC_ID_BRENDER_PIX,
300  .p.capabilities = AV_CODEC_CAP_DR1,
302 };
FF_ENABLE_DEPRECATION_WARNINGS
#define FF_ENABLE_DEPRECATION_WARNINGS
Definition: internal.h:73
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
pix_decode_header
static int pix_decode_header(PixHeader *out, GetByteContext *pgb)
Definition: brenderpix.c:114
AVFrame::palette_has_changed
attribute_deprecated int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:546
AV_PIX_FMT_YA8
@ AV_PIX_FMT_YA8
8 bits gray, 8 bits alpha
Definition: pixfmt.h:133
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:340
AVPacket::data
uint8_t * data
Definition: packet.h:491
FFCodec
Definition: codec_internal.h:127
AVFrame::flags
int flags
Frame flags, a combination of AV_FRAME_FLAGS.
Definition: frame.h:649
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:94
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
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:361
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:374
IMAGE_DATA_CHUNK
#define IMAGE_DATA_CHUNK
Definition: brenderpix.c:33
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:168
HEADER2_CHUNK
#define HEADER2_CHUNK
Definition: brenderpix.c:32
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
PixHeader::format
int format
Definition: brenderpix.c:111
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
AV_FRAME_FLAG_KEY
#define AV_FRAME_FLAG_KEY
A flag to mark frames that are keyframes.
Definition: frame.h:628
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:306
pix_decode_frame
static int pix_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt)
Definition: brenderpix.c:133
decode.h
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:272
frame
static AVFrame * frame
Definition: demux_decode.c:54
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:279
PixHeader::width
int width
Definition: brenderpix.c:109
std_pal_table
static const uint32_t std_pal_table[256]
Definition: brenderpix.c:45
bytestream2_get_bytes_left
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:158
bytestream2_tell
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:192
AVFrame::pict_type
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:442
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1617
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() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:52
AVPacket::size
int size
Definition: packet.h:492
codec_internal.h
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:255
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:658
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
ff_brender_pix_decoder
const FFCodec ff_brender_pix_decoder
Definition: brenderpix.c:295
AVCodecContext
main external API structure.
Definition: avcodec.h:441
PixHeader
Definition: brenderpix.c:108
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
FF_DISABLE_DEPRECATION_WARNINGS
#define FF_DISABLE_DEPRECATION_WARNINGS
Definition: internal.h:72
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
avpriv_request_sample
#define avpriv_request_sample(...)
Definition: tableprint_vlc.h:36
AVPacket
This structure stores compressed data.
Definition: packet.h:468
PixHeader::height
int height
Definition: brenderpix.c:110
HEADER1_CHUNK
#define HEADER1_CHUNK
Definition: brenderpix.c:31
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:137
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:385
AV_PIX_FMT_0RGB
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Definition: pixfmt.h:255
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AV_CODEC_ID_BRENDER_PIX
@ AV_CODEC_ID_BRENDER_PIX
Definition: codec_id.h:230
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61