FFmpeg  4.0
cdxl.c
Go to the documentation of this file.
1 /*
2  * CDXL video decoder
3  * Copyright (c) 2011-2012 Paul B Mahol
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  * @file
24  * Commodore CDXL video decoder
25  * @author Paul B Mahol
26  */
27 
28 #define UNCHECKED_BITSTREAM_READER 1
29 
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/imgutils.h"
32 #include "avcodec.h"
33 #include "bytestream.h"
34 #include "get_bits.h"
35 #include "internal.h"
36 
37 #define BIT_PLANAR 0x00
38 #define CHUNKY 0x20
39 #define BYTE_PLANAR 0x40
40 #define BIT_LINE 0x80
41 #define BYTE_LINE 0xC0
42 
43 typedef struct CDXLVideoContext {
45  int bpp;
46  int format;
48  const uint8_t *palette;
50  const uint8_t *video;
55 
57 {
58  CDXLVideoContext *c = avctx->priv_data;
59 
60  c->new_video_size = 0;
61  c->avctx = avctx;
62 
63  return 0;
64 }
65 
66 static void import_palette(CDXLVideoContext *c, uint32_t *new_palette)
67 {
68  int i;
69 
70  for (i = 0; i < c->palette_size / 2; i++) {
71  unsigned rgb = AV_RB16(&c->palette[i * 2]);
72  unsigned r = ((rgb >> 8) & 0xF) * 0x11;
73  unsigned g = ((rgb >> 4) & 0xF) * 0x11;
74  unsigned b = (rgb & 0xF) * 0x11;
75  AV_WN32(&new_palette[i], (0xFFU << 24) | (r << 16) | (g << 8) | b);
76  }
77 }
78 
79 static void bitplanar2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
80 {
81  GetBitContext gb;
82  int x, y, plane;
83 
84  if (init_get_bits8(&gb, c->video, c->video_size) < 0)
85  return;
86  for (plane = 0; plane < c->bpp; plane++) {
87  for (y = 0; y < c->avctx->height; y++) {
88  for (x = 0; x < c->avctx->width; x++)
89  out[linesize * y + x] |= get_bits1(&gb) << plane;
90  skip_bits(&gb, c->padded_bits);
91  }
92  }
93 }
94 
95 static void bitline2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
96 {
97  GetBitContext gb;
98  int x, y, plane;
99 
100  if (init_get_bits8(&gb, c->video, c->video_size) < 0)
101  return;
102  for (y = 0; y < c->avctx->height; y++) {
103  for (plane = 0; plane < c->bpp; plane++) {
104  for (x = 0; x < c->avctx->width; x++)
105  out[linesize * y + x] |= get_bits1(&gb) << plane;
106  skip_bits(&gb, c->padded_bits);
107  }
108  }
109 }
110 
111 static void chunky2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
112 {
113  GetByteContext gb;
114  int y;
115 
116  bytestream2_init(&gb, c->video, c->video_size);
117  for (y = 0; y < c->avctx->height; y++) {
118  bytestream2_get_buffer(&gb, out + linesize * y, c->avctx->width * 3);
119  }
120 }
121 
122 static void import_format(CDXLVideoContext *c, int linesize, uint8_t *out)
123 {
124  memset(out, 0, linesize * c->avctx->height);
125 
126  switch (c->format) {
127  case BIT_PLANAR:
128  bitplanar2chunky(c, linesize, out);
129  break;
130  case BIT_LINE:
131  bitline2chunky(c, linesize, out);
132  break;
133  case CHUNKY:
134  chunky2chunky(c, linesize, out);
135  break;
136  }
137 }
138 
140 {
141  uint32_t *new_palette = (uint32_t *)frame->data[1];
142 
143  memset(frame->data[1], 0, AVPALETTE_SIZE);
144  import_palette(c, new_palette);
145  import_format(c, frame->linesize[0], frame->data[0]);
146 }
147 
149 {
150  import_format(c, frame->linesize[0], frame->data[0]);
151 }
152 
154 {
155  AVCodecContext *avctx = c->avctx;
156  uint32_t new_palette[16], r, g, b;
157  uint8_t *ptr, *out, index, op;
158  int x, y;
159 
160  ptr = c->new_video;
161  out = frame->data[0];
162 
163  import_palette(c, new_palette);
164  import_format(c, avctx->width, c->new_video);
165 
166  for (y = 0; y < avctx->height; y++) {
167  r = new_palette[0] & 0xFF0000;
168  g = new_palette[0] & 0xFF00;
169  b = new_palette[0] & 0xFF;
170  for (x = 0; x < avctx->width; x++) {
171  index = *ptr++;
172  op = index >> 4;
173  index &= 15;
174  switch (op) {
175  case 0:
176  r = new_palette[index] & 0xFF0000;
177  g = new_palette[index] & 0xFF00;
178  b = new_palette[index] & 0xFF;
179  break;
180  case 1:
181  b = index * 0x11;
182  break;
183  case 2:
184  r = index * 0x11 << 16;
185  break;
186  case 3:
187  g = index * 0x11 << 8;
188  break;
189  }
190  AV_WL24(out + x * 3, r | g | b);
191  }
192  out += frame->linesize[0];
193  }
194 }
195 
197 {
198  AVCodecContext *avctx = c->avctx;
199  uint32_t new_palette[64], r, g, b;
200  uint8_t *ptr, *out, index, op;
201  int x, y;
202 
203  ptr = c->new_video;
204  out = frame->data[0];
205 
206  import_palette(c, new_palette);
207  import_format(c, avctx->width, c->new_video);
208 
209  for (y = 0; y < avctx->height; y++) {
210  r = new_palette[0] & 0xFF0000;
211  g = new_palette[0] & 0xFF00;
212  b = new_palette[0] & 0xFF;
213  for (x = 0; x < avctx->width; x++) {
214  index = *ptr++;
215  op = index >> 6;
216  index &= 63;
217  switch (op) {
218  case 0:
219  r = new_palette[index] & 0xFF0000;
220  g = new_palette[index] & 0xFF00;
221  b = new_palette[index] & 0xFF;
222  break;
223  case 1:
224  b = (index << 2) | (b & 3);
225  break;
226  case 2:
227  r = (index << 18) | (r & (3 << 16));
228  break;
229  case 3:
230  g = (index << 10) | (g & (3 << 8));
231  break;
232  }
233  AV_WL24(out + x * 3, r | g | b);
234  }
235  out += frame->linesize[0];
236  }
237 }
238 
240  int *got_frame, AVPacket *pkt)
241 {
242  CDXLVideoContext *c = avctx->priv_data;
243  AVFrame * const p = data;
244  int ret, w, h, encoding, aligned_width, buf_size = pkt->size;
245  const uint8_t *buf = pkt->data;
246 
247  if (buf_size < 32)
248  return AVERROR_INVALIDDATA;
249  encoding = buf[1] & 7;
250  c->format = buf[1] & 0xE0;
251  w = AV_RB16(&buf[14]);
252  h = AV_RB16(&buf[16]);
253  c->bpp = buf[19];
254  c->palette_size = AV_RB16(&buf[20]);
255  c->palette = buf + 32;
256  c->video = c->palette + c->palette_size;
257  c->video_size = buf_size - c->palette_size - 32;
258 
259  if (c->palette_size > 512)
260  return AVERROR_INVALIDDATA;
261  if (buf_size < c->palette_size + 32)
262  return AVERROR_INVALIDDATA;
263  if (c->bpp < 1)
264  return AVERROR_INVALIDDATA;
265  if (c->format != BIT_PLANAR && c->format != BIT_LINE && c->format != CHUNKY) {
266  avpriv_request_sample(avctx, "Pixel format 0x%0x", c->format);
267  return AVERROR_PATCHWELCOME;
268  }
269 
270  if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
271  return ret;
272 
273  if (c->format == CHUNKY)
274  aligned_width = avctx->width;
275  else
276  aligned_width = FFALIGN(c->avctx->width, 16);
277  c->padded_bits = aligned_width - c->avctx->width;
278  if (c->video_size < aligned_width * avctx->height * (int64_t)c->bpp / 8)
279  return AVERROR_INVALIDDATA;
280  if (!encoding && c->palette_size && c->bpp <= 8 && c->format != CHUNKY) {
281  avctx->pix_fmt = AV_PIX_FMT_PAL8;
282  } else if (encoding == 1 && (c->bpp == 6 || c->bpp == 8) && c->format != CHUNKY) {
283  if (c->palette_size != (1 << (c->bpp - 1)))
284  return AVERROR_INVALIDDATA;
285  avctx->pix_fmt = AV_PIX_FMT_BGR24;
286  } else if (!encoding && c->bpp == 24 && c->format == CHUNKY &&
287  !c->palette_size) {
288  avctx->pix_fmt = AV_PIX_FMT_RGB24;
289  } else {
290  avpriv_request_sample(avctx, "Encoding %d, bpp %d and format 0x%x",
291  encoding, c->bpp, c->format);
292  return AVERROR_PATCHWELCOME;
293  }
294 
295  if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
296  return ret;
298 
299  if (encoding) {
302  if (!c->new_video)
303  return AVERROR(ENOMEM);
304  if (c->bpp == 8)
305  cdxl_decode_ham8(c, p);
306  else
307  cdxl_decode_ham6(c, p);
308  } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
309  cdxl_decode_rgb(c, p);
310  } else {
311  cdxl_decode_raw(c, p);
312  }
313  *got_frame = 1;
314 
315  return buf_size;
316 }
317 
319 {
320  CDXLVideoContext *c = avctx->priv_data;
321 
322  av_freep(&c->new_video);
323 
324  return 0;
325 }
326 
328  .name = "cdxl",
329  .long_name = NULL_IF_CONFIG_SMALL("Commodore CDXL video"),
330  .type = AVMEDIA_TYPE_VIDEO,
331  .id = AV_CODEC_ID_CDXL,
332  .priv_data_size = sizeof(CDXLVideoContext),
334  .close = cdxl_decode_end,
336  .capabilities = AV_CODEC_CAP_DR1,
337 };
int plane
Definition: avisynth_c.h:422
#define BIT_LINE
Definition: cdxl.c:40
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
This structure describes decoded (raw) audio or video data.
Definition: frame.h:218
int format
Definition: cdxl.c:46
misc image utilities
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:64
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Check that the provided frame dimensions are valid and set them on the codec context.
Definition: utils.c:104
const char * g
Definition: vf_curves.c:112
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
int video_size
Definition: cdxl.c:51
int size
Definition: avcodec.h:1431
const char * b
Definition: vf_curves.c:113
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1727
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size)
Same behaviour av_fast_malloc but the buffer has additional AV_INPUT_BUFFER_PADDING_SIZE at the end w...
Definition: utils.c:70
static void cdxl_decode_ham8(CDXLVideoContext *c, AVFrame *frame)
Definition: cdxl.c:196
static AVPacket pkt
AVCodec.
Definition: avcodec.h:3408
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:42
const uint8_t * palette
Definition: cdxl.c:48
#define AV_WL24(p, d)
Definition: intreadwrite.h:464
void void avpriv_request_sample(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
uint8_t
#define av_cold
Definition: attributes.h:82
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:73
#define AVPALETTE_SIZE
Definition: pixfmt.h:32
AVCodec ff_cdxl_decoder
Definition: cdxl.c:327
static AVFrame * frame
static av_cold int cdxl_decode_end(AVCodecContext *avctx)
Definition: cdxl.c:318
const char data[16]
Definition: mxf.c:90
uint8_t * data
Definition: avcodec.h:1430
static void chunky2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
Definition: cdxl.c:111
bitstream reader API header.
#define FFALIGN(x, a)
Definition: macros.h:48
static int cdxl_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *pkt)
Definition: cdxl.c:239
#define AV_RB16
Definition: intreadwrite.h:53
#define AVERROR(e)
Definition: error.h:43
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
const char * r
Definition: vf_curves.c:111
static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:263
const char * name
Name of the codec implementation.
Definition: avcodec.h:3415
static void bitline2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
Definition: cdxl.c:95
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:301
#define CHUNKY
Definition: cdxl.c:38
int width
picture width / height.
Definition: avcodec.h:1690
uint8_t w
Definition: llviddspenc.c:38
static av_cold int cdxl_decode_init(AVCodecContext *avctx)
Definition: cdxl.c:56
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:65
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
Libavcodec external API header.
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:249
static int init_get_bits8(GetBitContext *s, const uint8_t *buffer, int byte_size)
Initialize GetBitContext.
Definition: get_bits.h:464
main external API structure.
Definition: avcodec.h:1518
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1891
void * buf
Definition: avisynth_c.h:690
AVCodecContext * avctx
Definition: cdxl.c:44
static unsigned int get_bits1(GetBitContext *s)
Definition: get_bits.h:321
static void skip_bits(GetBitContext *s, int n)
Definition: get_bits.h:314
int index
Definition: gxfenc.c:89
uint8_t * new_video
Definition: cdxl.c:52
#define BIT_PLANAR
Definition: cdxl.c:37
int new_video_size
Definition: cdxl.c:53
static void bitplanar2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
Definition: cdxl.c:79
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:232
static void cdxl_decode_rgb(CDXLVideoContext *c, AVFrame *frame)
Definition: cdxl.c:139
static int op(uint8_t **dst, const uint8_t *dst_end, GetByteContext *gb, int pixel, int count, int *x, int width, int linesize)
Perform decode operation.
Definition: anm.c:78
common internal api header.
#define AV_WN32(p, v)
Definition: intreadwrite.h:376
static double c[64]
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding...
Definition: avcodec.h:773
void * priv_data
Definition: avcodec.h:1545
static void cdxl_decode_ham6(CDXLVideoContext *c, AVFrame *frame)
Definition: cdxl.c:153
const uint8_t * video
Definition: cdxl.c:50
FILE * out
Definition: movenc.c:54
static void import_format(CDXLVideoContext *c, int linesize, uint8_t *out)
Definition: cdxl.c:122
#define av_freep(p)
int palette_size
Definition: cdxl.c:49
int padded_bits
Definition: cdxl.c:47
This structure stores compressed data.
Definition: avcodec.h:1407
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:959
static void import_palette(CDXLVideoContext *c, uint32_t *new_palette)
Definition: cdxl.c:66
static void cdxl_decode_raw(CDXLVideoContext *c, AVFrame *frame)
Definition: cdxl.c:148