]> git.sesse.net Git - ffmpeg/blob - libavcodec/brender_pix.c
Merge commit 'e4d349b4014ee2a03f521027e0bd1ace4a9e60bd'
[ffmpeg] / libavcodec / brender_pix.c
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 /*
23  * Tested against samples from I-War / Independence War and Defiance.
24  * If the PIX file does not contain a palette, the
25  * palette_has_changed property of the AVFrame is set to 0.
26  */
27
28 #include "libavutil/imgutils.h"
29 #include "avcodec.h"
30 #include "bytestream.h"
31
32 typedef struct BRPixContext {
33     AVFrame frame;
34 } BRPixContext;
35
36 typedef struct BRPixHeader {
37     int format;
38     unsigned int width, height;
39 } BRPixHeader;
40
41 static av_cold int brpix_init(AVCodecContext *avctx)
42 {
43     BRPixContext *s = avctx->priv_data;
44
45     avcodec_get_frame_defaults(&s->frame);
46     avctx->coded_frame = &s->frame;
47
48     return 0;
49 }
50
51 static int brpix_decode_header(BRPixHeader *out, GetByteContext *pgb)
52 {
53     unsigned int header_len = bytestream2_get_be32(pgb);
54
55     out->format = bytestream2_get_byte(pgb);
56     bytestream2_skip(pgb, 2);
57     out->width = bytestream2_get_be16(pgb);
58     out->height = bytestream2_get_be16(pgb);
59
60     // the header is at least 11 bytes long; we read the first 7
61     if (header_len < 11) {
62         return 0;
63     }
64
65     // skip the rest of the header
66     bytestream2_skip(pgb, header_len-7);
67
68     return 1;
69 }
70
71 static int brpix_decode_frame(AVCodecContext *avctx,
72                               void *data, int *data_size_out,
73                               AVPacket *avpkt)
74 {
75     BRPixContext *s = avctx->priv_data;
76     AVFrame *frame_out = data;
77
78     int ret;
79     GetByteContext gb;
80
81     unsigned int bytes_pp;
82
83     unsigned int magic[4];
84     unsigned int chunk_type;
85     unsigned int data_len;
86     BRPixHeader hdr;
87
88     bytestream2_init(&gb, avpkt->data, avpkt->size);
89
90     magic[0] = bytestream2_get_be32(&gb);
91     magic[1] = bytestream2_get_be32(&gb);
92     magic[2] = bytestream2_get_be32(&gb);
93     magic[3] = bytestream2_get_be32(&gb);
94
95     if (magic[0] != 0x12 ||
96         magic[1] != 0x8 ||
97         magic[2] != 0x2 ||
98         magic[3] != 0x2) {
99         av_log(avctx, AV_LOG_ERROR, "Not a BRender PIX file\n");
100         return AVERROR_INVALIDDATA;
101     }
102
103     chunk_type = bytestream2_get_be32(&gb);
104     if (chunk_type != 0x3 && chunk_type != 0x3d) {
105         av_log(avctx, AV_LOG_ERROR, "Invalid chunk type %d\n", chunk_type);
106         return AVERROR_INVALIDDATA;
107     }
108
109     ret = brpix_decode_header(&hdr, &gb);
110     if (!ret) {
111         av_log(avctx, AV_LOG_ERROR, "Invalid header length\n");
112         return AVERROR_INVALIDDATA;
113     }
114     switch (hdr.format) {
115     case 3:
116         avctx->pix_fmt = AV_PIX_FMT_PAL8;
117         bytes_pp = 1;
118         break;
119     case 4:
120         avctx->pix_fmt = AV_PIX_FMT_RGB555BE;
121         bytes_pp = 2;
122         break;
123     case 5:
124         avctx->pix_fmt = AV_PIX_FMT_RGB565BE;
125         bytes_pp = 2;
126         break;
127     case 6:
128         avctx->pix_fmt = AV_PIX_FMT_RGB24;
129         bytes_pp = 3;
130         break;
131     case 7:
132         avctx->pix_fmt = AV_PIX_FMT_0RGB;
133         bytes_pp = 4;
134         break;
135     case 18:
136         avctx->pix_fmt = AV_PIX_FMT_GRAY8A;
137         bytes_pp = 2;
138         break;
139     default:
140         av_log(avctx, AV_LOG_ERROR, "Format %d is not supported\n",
141                                     hdr.format);
142         return AVERROR_PATCHWELCOME;
143     }
144
145     if (s->frame.data[0])
146         avctx->release_buffer(avctx, &s->frame);
147
148     if (av_image_check_size(hdr.width, hdr.height, 0, avctx) < 0)
149         return AVERROR_INVALIDDATA;
150
151     if (hdr.width != avctx->width || hdr.height != avctx->height)
152         avcodec_set_dimensions(avctx, hdr.width, hdr.height);
153
154     if ((ret = avctx->get_buffer(avctx, &s->frame)) < 0) {
155         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
156         return ret;
157     }
158
159     chunk_type = bytestream2_get_be32(&gb);
160
161     if (avctx->pix_fmt == AV_PIX_FMT_PAL8 &&
162         (chunk_type == 0x3 || chunk_type == 0x3d)) {
163         BRPixHeader palhdr;
164         uint32_t *pal_out = (uint32_t *)s->frame.data[1];
165         int i;
166
167         ret = brpix_decode_header(&palhdr, &gb);
168         if (!ret) {
169             av_log(avctx, AV_LOG_ERROR, "Invalid palette header length\n");
170             return AVERROR_INVALIDDATA;
171         }
172         if (palhdr.format != 7) {
173             av_log(avctx, AV_LOG_ERROR, "Palette is not in 0RGB format\n");
174             return AVERROR_INVALIDDATA;
175         }
176
177         chunk_type = bytestream2_get_be32(&gb);
178         data_len = bytestream2_get_be32(&gb);
179         bytestream2_skip(&gb, 8);
180         if (chunk_type != 0x21 || data_len != 1032 ||
181             bytestream2_get_bytes_left(&gb) < 1032) {
182             av_log(avctx, AV_LOG_ERROR, "Invalid palette data\n");
183             return AVERROR_INVALIDDATA;
184         }
185         // convert 0RGB to machine endian format (ARGB32)
186         for (i = 0; i < 256; ++i) {
187             bytestream2_skipu(&gb, 1);
188             *pal_out++ = (0xFFU << 24) | bytestream2_get_be24u(&gb);
189         }
190         bytestream2_skip(&gb, 8);
191
192         s->frame.palette_has_changed = 1;
193
194         chunk_type = bytestream2_get_be32(&gb);
195     }
196
197     data_len = bytestream2_get_be32(&gb);
198     bytestream2_skip(&gb, 8);
199
200     // read the image data to the buffer
201     {
202         unsigned int bytes_per_scanline = bytes_pp * hdr.width;
203         unsigned int bytes_left = bytestream2_get_bytes_left(&gb);
204
205         if (chunk_type != 0x21 || data_len != bytes_left ||
206             bytes_left / bytes_per_scanline < hdr.height)
207         {
208             av_log(avctx, AV_LOG_ERROR, "Invalid image data\n");
209             return AVERROR_INVALIDDATA;
210         }
211
212         av_image_copy_plane(s->frame.data[0], s->frame.linesize[0],
213                             avpkt->data + bytestream2_tell(&gb),
214                             bytes_per_scanline,
215                             bytes_per_scanline, hdr.height);
216     }
217
218     *frame_out = s->frame;
219     *data_size_out = sizeof(AVFrame);
220
221     return avpkt->size;
222 }
223
224 static av_cold int brpix_end(AVCodecContext *avctx)
225 {
226     BRPixContext *s = avctx->priv_data;
227
228     if(s->frame.data[0])
229         avctx->release_buffer(avctx, &s->frame);
230
231     return 0;
232 }
233
234 AVCodec ff_brender_pix_decoder = {
235     .name           = "brender_pix",
236     .type           = AVMEDIA_TYPE_VIDEO,
237     .id             = AV_CODEC_ID_BRENDER_PIX,
238     .priv_data_size = sizeof(BRPixContext),
239     .init           = brpix_init,
240     .close          = brpix_end,
241     .decode         = brpix_decode_frame,
242     .capabilities   = CODEC_CAP_DR1,
243     .long_name      = NULL_IF_CONFIG_SMALL("BRender PIX image"),
244 };