• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "internal.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 
pix_decode_header(PixHeader * out,GetByteContext * pgb)114 static int pix_decode_header(PixHeader *out, GetByteContext *pgb)
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 
pix_decode_frame(AVCodecContext * avctx,AVFrame * frame,int * got_frame,AVPacket * avpkt)133 static int pix_decode_frame(AVCodecContext *avctx, AVFrame *frame,
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         frame->palette_has_changed = 1;
249 
250         chunk_type = bytestream2_get_be32(&gb);
251     } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
252         /* no palette supplied, use the default one */
253         uint32_t *pal_out = (uint32_t *)frame->data[1];
254 
255         // TODO: add an AVOption to load custom palette files
256         av_log(avctx, AV_LOG_WARNING,
257                "Using default palette, colors might be off.\n");
258         memcpy(pal_out, std_pal_table, sizeof(uint32_t) * 256);
259 
260         frame->palette_has_changed = 1;
261     }
262 
263     data_len = bytestream2_get_be32(&gb);
264     bytestream2_skip(&gb, 8);
265 
266     // read the image data to the buffer
267     bytes_left = bytestream2_get_bytes_left(&gb);
268 
269     if (chunk_type != IMAGE_DATA_CHUNK || data_len != bytes_left ||
270         bytes_left / bytes_per_scanline < hdr.height) {
271         av_log(avctx, AV_LOG_ERROR, "Invalid image data.\n");
272         return AVERROR_INVALIDDATA;
273     }
274 
275     av_image_copy_plane(frame->data[0], frame->linesize[0],
276                         avpkt->data + bytestream2_tell(&gb),
277                         bytes_per_scanline,
278                         bytes_per_scanline, hdr.height);
279 
280     frame->pict_type = AV_PICTURE_TYPE_I;
281     frame->key_frame = 1;
282     *got_frame = 1;
283 
284     return avpkt->size;
285 }
286 
287 const FFCodec ff_brender_pix_decoder = {
288     .p.name         = "brender_pix",
289     .p.long_name    = NULL_IF_CONFIG_SMALL("BRender PIX image"),
290     .p.type         = AVMEDIA_TYPE_VIDEO,
291     .p.id           = AV_CODEC_ID_BRENDER_PIX,
292     .p.capabilities = AV_CODEC_CAP_DR1,
293     FF_CODEC_DECODE_CB(pix_decode_frame),
294 };
295