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 */ 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; 110 int height; 111 int format; 112} PixHeader; 113 114static 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 133static 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 287const 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