Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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
#include "internal.h"
32
 
33
typedef struct BRPixHeader {
34
    int format;
35
    unsigned int width, height;
36
} BRPixHeader;
37
 
38
static int brpix_decode_header(BRPixHeader *out, GetByteContext *pgb)
39
{
40
    unsigned int header_len = bytestream2_get_be32(pgb);
41
 
42
    out->format = bytestream2_get_byte(pgb);
43
    bytestream2_skip(pgb, 2);
44
    out->width = bytestream2_get_be16(pgb);
45
    out->height = bytestream2_get_be16(pgb);
46
 
47
    // the header is at least 11 bytes long; we read the first 7
48
    if (header_len < 11) {
49
        return 0;
50
    }
51
 
52
    // skip the rest of the header
53
    bytestream2_skip(pgb, header_len-7);
54
 
55
    return 1;
56
}
57
 
58
static int brpix_decode_frame(AVCodecContext *avctx,
59
                              void *data, int *got_frame,
60
                              AVPacket *avpkt)
61
{
62
    AVFrame *frame = data;
63
 
64
    int ret;
65
    GetByteContext gb;
66
 
67
    unsigned int bytes_pp;
68
 
69
    unsigned int magic[4];
70
    unsigned int chunk_type;
71
    unsigned int data_len;
72
    BRPixHeader hdr;
73
 
74
    bytestream2_init(&gb, avpkt->data, avpkt->size);
75
 
76
    magic[0] = bytestream2_get_be32(&gb);
77
    magic[1] = bytestream2_get_be32(&gb);
78
    magic[2] = bytestream2_get_be32(&gb);
79
    magic[3] = bytestream2_get_be32(&gb);
80
 
81
    if (magic[0] != 0x12 ||
82
        magic[1] != 0x8 ||
83
        magic[2] != 0x2 ||
84
        magic[3] != 0x2) {
85
        av_log(avctx, AV_LOG_ERROR, "Not a BRender PIX file\n");
86
        return AVERROR_INVALIDDATA;
87
    }
88
 
89
    chunk_type = bytestream2_get_be32(&gb);
90
    if (chunk_type != 0x3 && chunk_type != 0x3d) {
91
        av_log(avctx, AV_LOG_ERROR, "Invalid chunk type %d\n", chunk_type);
92
        return AVERROR_INVALIDDATA;
93
    }
94
 
95
    ret = brpix_decode_header(&hdr, &gb);
96
    if (!ret) {
97
        av_log(avctx, AV_LOG_ERROR, "Invalid header length\n");
98
        return AVERROR_INVALIDDATA;
99
    }
100
    switch (hdr.format) {
101
    case 3:
102
        avctx->pix_fmt = AV_PIX_FMT_PAL8;
103
        bytes_pp = 1;
104
        break;
105
    case 4:
106
        avctx->pix_fmt = AV_PIX_FMT_RGB555BE;
107
        bytes_pp = 2;
108
        break;
109
    case 5:
110
        avctx->pix_fmt = AV_PIX_FMT_RGB565BE;
111
        bytes_pp = 2;
112
        break;
113
    case 6:
114
        avctx->pix_fmt = AV_PIX_FMT_RGB24;
115
        bytes_pp = 3;
116
        break;
117
    case 7:
118
        avctx->pix_fmt = AV_PIX_FMT_0RGB;
119
        bytes_pp = 4;
120
        break;
121
    case 18:
122
        avctx->pix_fmt = AV_PIX_FMT_GRAY8A;
123
        bytes_pp = 2;
124
        break;
125
    default:
126
        av_log(avctx, AV_LOG_ERROR, "Format %d is not supported\n",
127
                                    hdr.format);
128
        return AVERROR_PATCHWELCOME;
129
    }
130
 
131
    if (av_image_check_size(hdr.width, hdr.height, 0, avctx) < 0)
132
        return AVERROR_INVALIDDATA;
133
 
134
    if (hdr.width != avctx->width || hdr.height != avctx->height)
135
        avcodec_set_dimensions(avctx, hdr.width, hdr.height);
136
 
137
    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
138
        return ret;
139
 
140
    chunk_type = bytestream2_get_be32(&gb);
141
 
142
    if (avctx->pix_fmt == AV_PIX_FMT_PAL8 &&
143
        (chunk_type == 0x3 || chunk_type == 0x3d)) {
144
        BRPixHeader palhdr;
145
        uint32_t *pal_out = (uint32_t *)frame->data[1];
146
        int i;
147
 
148
        ret = brpix_decode_header(&palhdr, &gb);
149
        if (!ret) {
150
            av_log(avctx, AV_LOG_ERROR, "Invalid palette header length\n");
151
            return AVERROR_INVALIDDATA;
152
        }
153
        if (palhdr.format != 7) {
154
            av_log(avctx, AV_LOG_ERROR, "Palette is not in 0RGB format\n");
155
            return AVERROR_INVALIDDATA;
156
        }
157
 
158
        chunk_type = bytestream2_get_be32(&gb);
159
        data_len = bytestream2_get_be32(&gb);
160
        bytestream2_skip(&gb, 8);
161
        if (chunk_type != 0x21 || data_len != 1032 ||
162
            bytestream2_get_bytes_left(&gb) < 1032) {
163
            av_log(avctx, AV_LOG_ERROR, "Invalid palette data\n");
164
            return AVERROR_INVALIDDATA;
165
        }
166
        // convert 0RGB to machine endian format (ARGB32)
167
        for (i = 0; i < 256; ++i) {
168
            bytestream2_skipu(&gb, 1);
169
            *pal_out++ = (0xFFU << 24) | bytestream2_get_be24u(&gb);
170
        }
171
        bytestream2_skip(&gb, 8);
172
 
173
        frame->palette_has_changed = 1;
174
 
175
        chunk_type = bytestream2_get_be32(&gb);
176
    } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
177
        uint32_t *pal_out = (uint32_t *)frame->data[1];
178
        int i;
179
 
180
        for (i = 0; i < 256; ++i) {
181
            *pal_out++ = (0xFFU << 24) | (i * 0x010101);
182
        }
183
        frame->palette_has_changed = 1;
184
    }
185
 
186
    data_len = bytestream2_get_be32(&gb);
187
    bytestream2_skip(&gb, 8);
188
 
189
    // read the image data to the buffer
190
    {
191
        unsigned int bytes_per_scanline = bytes_pp * hdr.width;
192
        unsigned int bytes_left = bytestream2_get_bytes_left(&gb);
193
 
194
        if (chunk_type != 0x21 || data_len != bytes_left ||
195
            bytes_left / bytes_per_scanline < hdr.height)
196
        {
197
            av_log(avctx, AV_LOG_ERROR, "Invalid image data\n");
198
            return AVERROR_INVALIDDATA;
199
        }
200
 
201
        av_image_copy_plane(frame->data[0], frame->linesize[0],
202
                            avpkt->data + bytestream2_tell(&gb),
203
                            bytes_per_scanline,
204
                            bytes_per_scanline, hdr.height);
205
    }
206
 
207
    *got_frame = 1;
208
 
209
    return avpkt->size;
210
}
211
 
212
AVCodec ff_brender_pix_decoder = {
213
    .name           = "brender_pix",
214
    .long_name      = NULL_IF_CONFIG_SMALL("BRender PIX image"),
215
    .type           = AVMEDIA_TYPE_VIDEO,
216
    .id             = AV_CODEC_ID_BRENDER_PIX,
217
    .decode         = brpix_decode_frame,
218
    .capabilities   = CODEC_CAP_DR1,
219
};