3 * Copyright (c) 2011-2012 Paul B Mahol
5 * This file is part of Libav.
7 * Libav 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.
12 * Libav 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/intreadwrite.h"
23 #include "libavutil/imgutils.h"
28 AVCodecContext *avctx;
31 const uint8_t *palette;
39 static av_cold int cdxl_decode_init(AVCodecContext *avctx)
41 CDXLVideoContext *c = avctx->priv_data;
43 avcodec_get_frame_defaults(&c->frame);
44 c->new_video_size = 0;
50 static void import_palette(CDXLVideoContext *c, uint32_t *new_palette)
54 for (i = 0; i < c->palette_size / 2; i++) {
55 unsigned rgb = AV_RB16(&c->palette[i * 2]);
56 unsigned r = ((rgb >> 8) & 0xF) * 0x11;
57 unsigned g = ((rgb >> 4) & 0xF) * 0x11;
58 unsigned b = (rgb & 0xF) * 0x11;
59 AV_WN32(&new_palette[i], (r << 16) | (g << 8) | b);
63 static void bitplanar2chunky(CDXLVideoContext *c, int width,
64 int linesize, uint8_t *out)
69 init_get_bits(&gb, c->video, c->video_size * 8);
70 memset(out, 0, linesize * c->avctx->height);
71 for (plane = 0; plane < c->bpp; plane++)
72 for (y = 0; y < c->avctx->height; y++)
73 for (x = 0; x < width; x++)
74 out[linesize * y + x] |= get_bits1(&gb) << plane;
77 static void cdxl_decode_rgb(CDXLVideoContext *c)
79 uint32_t *new_palette = (uint32_t *)c->frame.data[1];
80 int padded_width = FFALIGN(c->avctx->width, 16);
82 import_palette(c, new_palette);
83 bitplanar2chunky(c, padded_width, c->frame.linesize[0], c->frame.data[0]);
86 static void cdxl_decode_ham6(CDXLVideoContext *c)
88 AVCodecContext *avctx = c->avctx;
89 uint32_t new_palette[16], r, g, b;
90 uint8_t *ptr, *out, index, op;
94 out = c->frame.data[0];
96 import_palette(c, new_palette);
97 bitplanar2chunky(c, avctx->width, avctx->width, c->new_video);
99 for (y = 0; y < avctx->height; y++) {
100 r = new_palette[0] & 0xFF0000;
101 g = new_palette[0] & 0xFF00;
102 b = new_palette[0] & 0xFF;
103 for (x = 0; x < avctx->width; x++) {
109 r = new_palette[index] & 0xFF0000;
110 g = new_palette[index] & 0xFF00;
111 b = new_palette[index] & 0xFF;
117 r = index * 0x11 << 16;
120 g = index * 0x11 << 8;
123 AV_WN32(out + x * 3, r | g | b);
125 out += c->frame.linesize[0];
129 static void cdxl_decode_ham8(CDXLVideoContext *c)
131 AVCodecContext *avctx = c->avctx;
132 uint32_t new_palette[64], r, g, b;
133 uint8_t *ptr, *out, index, op;
137 out = c->frame.data[0];
139 import_palette(c, new_palette);
140 bitplanar2chunky(c, avctx->width, avctx->width, c->new_video);
142 for (y = 0; y < avctx->height; y++) {
143 r = new_palette[0] & 0xFF0000;
144 g = new_palette[0] & 0xFF00;
145 b = new_palette[0] & 0xFF;
146 for (x = 0; x < avctx->width; x++) {
152 r = new_palette[index] & 0xFF0000;
153 g = new_palette[index] & 0xFF00;
154 b = new_palette[index] & 0xFF;
157 b = (index << 2) | (b & 3);
160 r = (index << 18) | (r & (3 << 16));
163 g = (index << 10) | (g & (3 << 8));
166 AV_WN32(out + x * 3, r | g | b);
168 out += c->frame.linesize[0];
172 static int cdxl_decode_frame(AVCodecContext *avctx, void *data,
173 int *data_size, AVPacket *pkt)
175 CDXLVideoContext *c = avctx->priv_data;
176 AVFrame * const p = &c->frame;
177 int ret, w, h, encoding, format, buf_size = pkt->size;
178 const uint8_t *buf = pkt->data;
181 return AVERROR_INVALIDDATA;
182 encoding = buf[1] & 7;
183 format = buf[1] & 0xE0;
184 w = AV_RB16(&buf[14]);
185 h = AV_RB16(&buf[16]);
187 c->palette_size = AV_RB16(&buf[20]);
188 c->palette = buf + 32;
189 c->video = c->palette + c->palette_size;
190 c->video_size = buf_size - c->palette_size - 32;
192 if (c->palette_size > 512)
193 return AVERROR_INVALIDDATA;
194 if (buf_size < c->palette_size + 32)
195 return AVERROR_INVALIDDATA;
197 return AVERROR_INVALIDDATA;
199 av_log_ask_for_sample(avctx, "unsupported pixel size: %d\n", c->bpp);
200 return AVERROR_PATCHWELCOME;
203 av_log_ask_for_sample(avctx, "unsupported pixel format: %d\n", format);
204 return AVERROR_PATCHWELCOME;
207 if ((ret = av_image_check_size(w, h, 0, avctx)) < 0)
209 if (w != avctx->width || h != avctx->height)
210 avcodec_set_dimensions(avctx, w, h);
213 if (c->video_size < FFALIGN(avctx->width, 16) *
214 avctx->height * c->bpp / 8)
215 return AVERROR_INVALIDDATA;
216 avctx->pix_fmt = PIX_FMT_PAL8;
217 } else if (encoding == 1 && (c->bpp == 6 || c->bpp == 8)) {
218 if (c->palette_size != (1 << (c->bpp - 1)))
219 return AVERROR_INVALIDDATA;
220 if (c->video_size < avctx->width * avctx->height * c->bpp / 8)
221 return AVERROR_INVALIDDATA;
222 avctx->pix_fmt = PIX_FMT_BGR24;
224 av_log_ask_for_sample(avctx, "unsupported encoding %d and bpp %d\n",
226 return AVERROR_PATCHWELCOME;
230 avctx->release_buffer(avctx, p);
233 if ((ret = avctx->get_buffer(avctx, p)) < 0) {
234 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
237 p->pict_type = AV_PICTURE_TYPE_I;
240 av_fast_padded_malloc(&c->new_video, &c->new_video_size,
241 h * w + FF_INPUT_BUFFER_PADDING_SIZE);
243 return AVERROR(ENOMEM);
251 *data_size = sizeof(AVFrame);
252 *(AVFrame*)data = c->frame;
257 static av_cold int cdxl_decode_end(AVCodecContext *avctx)
259 CDXLVideoContext *c = avctx->priv_data;
261 av_free(c->new_video);
262 if (c->frame.data[0])
263 avctx->release_buffer(avctx, &c->frame);
268 AVCodec ff_cdxl_decoder = {
270 .type = AVMEDIA_TYPE_VIDEO,
272 .priv_data_size = sizeof(CDXLVideoContext),
273 .init = cdxl_decode_init,
274 .close = cdxl_decode_end,
275 .decode = cdxl_decode_frame,
276 .capabilities = CODEC_CAP_DR1,
277 .long_name = NULL_IF_CONFIG_SMALL("Commodore CDXL video"),