FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
smc.c
Go to the documentation of this file.
1 /*
2  * Quicktime Graphics (SMC) Video Decoder
3  * Copyright (c) 2003 The FFmpeg Project
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  * QT SMC Video Decoder by Mike Melanson (melanson@pcisys.net)
25  * For more information about the SMC format, visit:
26  * http://www.pcisys.net/~melanson/codecs/
27  *
28  * The SMC decoder outputs PAL8 colorspace data.
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "libavutil/intreadwrite.h"
36 #include "avcodec.h"
37 #include "bytestream.h"
38 #include "internal.h"
39 
40 #define CPAIR 2
41 #define CQUAD 4
42 #define COCTET 8
43 
44 #define COLORS_PER_TABLE 256
45 
46 typedef struct SmcContext {
47 
50 
52 
53  /* SMC color tables */
57 
58  uint32_t pal[256];
59 } SmcContext;
60 
61 #define GET_BLOCK_COUNT() \
62  (opcode & 0x10) ? (1 + bytestream2_get_byte(&s->gb)) : 1 + (opcode & 0x0F);
63 
64 #define ADVANCE_BLOCK() \
65 { \
66  pixel_ptr += 4; \
67  if (pixel_ptr >= width) \
68  { \
69  pixel_ptr = 0; \
70  row_ptr += stride * 4; \
71  } \
72  total_blocks--; \
73  if (total_blocks < !!n_blocks) \
74  { \
75  av_log(s->avctx, AV_LOG_INFO, "warning: block counter just went negative (this should not happen)\n"); \
76  return; \
77  } \
78 }
79 
81 {
82  int width = s->avctx->width;
83  int height = s->avctx->height;
84  int stride = s->frame->linesize[0];
85  int i;
86  int chunk_size;
87  int buf_size = bytestream2_size(&s->gb);
88  unsigned char opcode;
89  int n_blocks;
90  unsigned int color_flags;
91  unsigned int color_flags_a;
92  unsigned int color_flags_b;
93  unsigned int flag_mask;
94 
95  unsigned char * const pixels = s->frame->data[0];
96 
97  int image_size = height * s->frame->linesize[0];
98  int row_ptr = 0;
99  int pixel_ptr = 0;
100  int pixel_x, pixel_y;
101  int row_inc = stride - 4;
102  int block_ptr;
103  int prev_block_ptr;
104  int prev_block_ptr1, prev_block_ptr2;
105  int prev_block_flag;
106  int total_blocks;
107  int color_table_index; /* indexes to color pair, quad, or octet tables */
108  int pixel;
109 
110  int color_pair_index = 0;
111  int color_quad_index = 0;
112  int color_octet_index = 0;
113 
114  /* make the palette available */
115  memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
116 
117  bytestream2_skip(&s->gb, 1);
118  chunk_size = bytestream2_get_be24(&s->gb);
119  if (chunk_size != buf_size)
120  av_log(s->avctx, AV_LOG_INFO, "warning: MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n",
121  chunk_size, buf_size);
122 
123  chunk_size = buf_size;
124  total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
125 
126  /* traverse through the blocks */
127  while (total_blocks) {
128  /* sanity checks */
129  /* make sure the row pointer hasn't gone wild */
130  if (row_ptr >= image_size) {
131  av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (row ptr = %d, height = %d)\n",
132  row_ptr, image_size);
133  return;
134  }
135 
136  opcode = bytestream2_get_byte(&s->gb);
137  switch (opcode & 0xF0) {
138  /* skip n blocks */
139  case 0x00:
140  case 0x10:
141  n_blocks = GET_BLOCK_COUNT();
142  while (n_blocks--) {
143  ADVANCE_BLOCK();
144  }
145  break;
146 
147  /* repeat last block n times */
148  case 0x20:
149  case 0x30:
150  n_blocks = GET_BLOCK_COUNT();
151 
152  /* sanity check */
153  if ((row_ptr == 0) && (pixel_ptr == 0)) {
154  av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but no blocks rendered yet\n",
155  opcode & 0xF0);
156  return;
157  }
158 
159  /* figure out where the previous block started */
160  if (pixel_ptr == 0)
161  prev_block_ptr1 =
162  (row_ptr - s->avctx->width * 4) + s->avctx->width - 4;
163  else
164  prev_block_ptr1 = row_ptr + pixel_ptr - 4;
165 
166  while (n_blocks--) {
167  block_ptr = row_ptr + pixel_ptr;
168  prev_block_ptr = prev_block_ptr1;
169  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
170  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
171  pixels[block_ptr++] = pixels[prev_block_ptr++];
172  }
173  block_ptr += row_inc;
174  prev_block_ptr += row_inc;
175  }
176  ADVANCE_BLOCK();
177  }
178  break;
179 
180  /* repeat previous pair of blocks n times */
181  case 0x40:
182  case 0x50:
183  n_blocks = GET_BLOCK_COUNT();
184  n_blocks *= 2;
185 
186  /* sanity check */
187  if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) {
188  av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n",
189  opcode & 0xF0);
190  return;
191  }
192 
193  /* figure out where the previous 2 blocks started */
194  if (pixel_ptr == 0)
195  prev_block_ptr1 = (row_ptr - s->avctx->width * 4) +
196  s->avctx->width - 4 * 2;
197  else if (pixel_ptr == 4)
198  prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc;
199  else
200  prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2;
201 
202  if (pixel_ptr == 0)
203  prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc;
204  else
205  prev_block_ptr2 = row_ptr + pixel_ptr - 4;
206 
207  prev_block_flag = 0;
208  while (n_blocks--) {
209  block_ptr = row_ptr + pixel_ptr;
210  if (prev_block_flag)
211  prev_block_ptr = prev_block_ptr2;
212  else
213  prev_block_ptr = prev_block_ptr1;
214  prev_block_flag = !prev_block_flag;
215 
216  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
217  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
218  pixels[block_ptr++] = pixels[prev_block_ptr++];
219  }
220  block_ptr += row_inc;
221  prev_block_ptr += row_inc;
222  }
223  ADVANCE_BLOCK();
224  }
225  break;
226 
227  /* 1-color block encoding */
228  case 0x60:
229  case 0x70:
230  n_blocks = GET_BLOCK_COUNT();
231  pixel = bytestream2_get_byte(&s->gb);
232 
233  while (n_blocks--) {
234  block_ptr = row_ptr + pixel_ptr;
235  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
236  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
237  pixels[block_ptr++] = pixel;
238  }
239  block_ptr += row_inc;
240  }
241  ADVANCE_BLOCK();
242  }
243  break;
244 
245  /* 2-color block encoding */
246  case 0x80:
247  case 0x90:
248  n_blocks = (opcode & 0x0F) + 1;
249 
250  /* figure out which color pair to use to paint the 2-color block */
251  if ((opcode & 0xF0) == 0x80) {
252  /* fetch the next 2 colors from bytestream and store in next
253  * available entry in the color pair table */
254  for (i = 0; i < CPAIR; i++) {
255  pixel = bytestream2_get_byte(&s->gb);
256  color_table_index = CPAIR * color_pair_index + i;
257  s->color_pairs[color_table_index] = pixel;
258  }
259  /* this is the base index to use for this block */
260  color_table_index = CPAIR * color_pair_index;
261  color_pair_index++;
262  /* wraparound */
263  if (color_pair_index == COLORS_PER_TABLE)
264  color_pair_index = 0;
265  } else
266  color_table_index = CPAIR * bytestream2_get_byte(&s->gb);
267 
268  while (n_blocks--) {
269  color_flags = bytestream2_get_be16(&s->gb);
270  flag_mask = 0x8000;
271  block_ptr = row_ptr + pixel_ptr;
272  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
273  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
274  if (color_flags & flag_mask)
275  pixel = color_table_index + 1;
276  else
277  pixel = color_table_index;
278  flag_mask >>= 1;
279  pixels[block_ptr++] = s->color_pairs[pixel];
280  }
281  block_ptr += row_inc;
282  }
283  ADVANCE_BLOCK();
284  }
285  break;
286 
287  /* 4-color block encoding */
288  case 0xA0:
289  case 0xB0:
290  n_blocks = (opcode & 0x0F) + 1;
291 
292  /* figure out which color quad to use to paint the 4-color block */
293  if ((opcode & 0xF0) == 0xA0) {
294  /* fetch the next 4 colors from bytestream and store in next
295  * available entry in the color quad table */
296  for (i = 0; i < CQUAD; i++) {
297  pixel = bytestream2_get_byte(&s->gb);
298  color_table_index = CQUAD * color_quad_index + i;
299  s->color_quads[color_table_index] = pixel;
300  }
301  /* this is the base index to use for this block */
302  color_table_index = CQUAD * color_quad_index;
303  color_quad_index++;
304  /* wraparound */
305  if (color_quad_index == COLORS_PER_TABLE)
306  color_quad_index = 0;
307  } else
308  color_table_index = CQUAD * bytestream2_get_byte(&s->gb);
309 
310  while (n_blocks--) {
311  color_flags = bytestream2_get_be32(&s->gb);
312  /* flag mask actually acts as a bit shift count here */
313  flag_mask = 30;
314  block_ptr = row_ptr + pixel_ptr;
315  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
316  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
317  pixel = color_table_index +
318  ((color_flags >> flag_mask) & 0x03);
319  flag_mask -= 2;
320  pixels[block_ptr++] = s->color_quads[pixel];
321  }
322  block_ptr += row_inc;
323  }
324  ADVANCE_BLOCK();
325  }
326  break;
327 
328  /* 8-color block encoding */
329  case 0xC0:
330  case 0xD0:
331  n_blocks = (opcode & 0x0F) + 1;
332 
333  /* figure out which color octet to use to paint the 8-color block */
334  if ((opcode & 0xF0) == 0xC0) {
335  /* fetch the next 8 colors from bytestream and store in next
336  * available entry in the color octet table */
337  for (i = 0; i < COCTET; i++) {
338  pixel = bytestream2_get_byte(&s->gb);
339  color_table_index = COCTET * color_octet_index + i;
340  s->color_octets[color_table_index] = pixel;
341  }
342  /* this is the base index to use for this block */
343  color_table_index = COCTET * color_octet_index;
344  color_octet_index++;
345  /* wraparound */
346  if (color_octet_index == COLORS_PER_TABLE)
347  color_octet_index = 0;
348  } else
349  color_table_index = COCTET * bytestream2_get_byte(&s->gb);
350 
351  while (n_blocks--) {
352  /*
353  For this input of 6 hex bytes:
354  01 23 45 67 89 AB
355  Mangle it to this output:
356  flags_a = xx012456, flags_b = xx89A37B
357  */
358  /* build the color flags */
359  int val1 = bytestream2_get_be16(&s->gb);
360  int val2 = bytestream2_get_be16(&s->gb);
361  int val3 = bytestream2_get_be16(&s->gb);
362  color_flags_a = ((val1 & 0xFFF0) << 8) | (val2 >> 4);
363  color_flags_b = ((val3 & 0xFFF0) << 8) |
364  ((val1 & 0x0F) << 8) | ((val2 & 0x0F) << 4) | (val3 & 0x0F);
365 
366  color_flags = color_flags_a;
367  /* flag mask actually acts as a bit shift count here */
368  flag_mask = 21;
369  block_ptr = row_ptr + pixel_ptr;
370  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
371  /* reload flags at third row (iteration pixel_y == 2) */
372  if (pixel_y == 2) {
373  color_flags = color_flags_b;
374  flag_mask = 21;
375  }
376  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
377  pixel = color_table_index +
378  ((color_flags >> flag_mask) & 0x07);
379  flag_mask -= 3;
380  pixels[block_ptr++] = s->color_octets[pixel];
381  }
382  block_ptr += row_inc;
383  }
384  ADVANCE_BLOCK();
385  }
386  break;
387 
388  /* 16-color block encoding (every pixel is a different color) */
389  case 0xE0:
390  n_blocks = (opcode & 0x0F) + 1;
391 
392  while (n_blocks--) {
393  block_ptr = row_ptr + pixel_ptr;
394  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
395  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
396  pixels[block_ptr++] = bytestream2_get_byte(&s->gb);
397  }
398  block_ptr += row_inc;
399  }
400  ADVANCE_BLOCK();
401  }
402  break;
403 
404  case 0xF0:
405  avpriv_request_sample(s->avctx, "0xF0 opcode");
406  break;
407  }
408  }
409 
410  return;
411 }
412 
414 {
415  SmcContext *s = avctx->priv_data;
416 
417  s->avctx = avctx;
418  avctx->pix_fmt = AV_PIX_FMT_PAL8;
419 
420  s->frame = av_frame_alloc();
421  if (!s->frame)
422  return AVERROR(ENOMEM);
423 
424  return 0;
425 }
426 
428  void *data, int *got_frame,
429  AVPacket *avpkt)
430 {
431  const uint8_t *buf = avpkt->data;
432  int buf_size = avpkt->size;
433  SmcContext *s = avctx->priv_data;
435  int ret;
436 
437  bytestream2_init(&s->gb, buf, buf_size);
438 
439  if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
440  return ret;
441 
442  if (pal) {
443  s->frame->palette_has_changed = 1;
444  memcpy(s->pal, pal, AVPALETTE_SIZE);
445  }
446 
448 
449  *got_frame = 1;
450  if ((ret = av_frame_ref(data, s->frame)) < 0)
451  return ret;
452 
453  /* always report that the buffer was completely consumed */
454  return buf_size;
455 }
456 
458 {
459  SmcContext *s = avctx->priv_data;
460 
461  av_frame_free(&s->frame);
462 
463  return 0;
464 }
465 
467  .name = "smc",
468  .long_name = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"),
469  .type = AVMEDIA_TYPE_VIDEO,
470  .id = AV_CODEC_ID_SMC,
471  .priv_data_size = sizeof(SmcContext),
473  .close = smc_decode_end,
475  .capabilities = AV_CODEC_CAP_DR1,
476 };
#define NULL
Definition: coverity.c:32
const char * s
Definition: avisynth_c.h:631
static av_cold int smc_decode_init(AVCodecContext *avctx)
Definition: smc.c:413
This structure describes decoded (raw) audio or video data.
Definition: frame.h:180
#define ADVANCE_BLOCK()
Definition: smc.c:64
Definition: smc.c:46
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
AVFrame * frame
Definition: smc.c:49
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
int size
Definition: avcodec.h:1578
uint32_t pal[256]
Definition: smc.c:58
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1870
static int smc_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: smc.c:427
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
AVCodec.
Definition: avcodec.h:3535
void void avpriv_request_sample(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
AVCodecContext * avctx
Definition: smc.c:48
uint8_t
#define av_cold
Definition: attributes.h:82
unsigned char color_quads[COLORS_PER_TABLE *CQUAD]
Definition: smc.c:55
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:140
8 bit with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:73
#define AVPALETTE_SIZE
Definition: pixfmt.h:32
#define CQUAD
Definition: smc.c:41
int av_frame_ref(AVFrame *dst, const AVFrame *src)
Set up a new reference to the data described by the source frame.
Definition: frame.c:374
uint8_t * data
Definition: avcodec.h:1577
#define av_log(a,...)
static av_always_inline int bytestream2_size(GetByteContext *g)
Definition: bytestream.h:198
#define AVERROR(e)
Definition: error.h:43
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:164
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:153
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:176
const char * name
Name of the codec implementation.
Definition: avcodec.h:3542
unsigned char color_pairs[COLORS_PER_TABLE *CPAIR]
Definition: smc.c:54
AVCodec ff_smc_decoder
Definition: smc.c:466
int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame)
Identical in function to av_frame_make_writable(), except it uses ff_get_buffer() to allocate the buf...
Definition: utils.c:977
GetByteContext gb
Definition: smc.c:51
int width
picture width / height.
Definition: avcodec.h:1829
#define width
#define CPAIR
Definition: smc.c:40
static av_cold int smc_decode_end(AVCodecContext *avctx)
Definition: smc.c:457
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
Libavcodec external API header.
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:211
unsigned char color_octets[COLORS_PER_TABLE *COCTET]
Definition: smc.c:56
main external API structure.
Definition: avcodec.h:1642
#define COCTET
Definition: smc.c:42
void * buf
Definition: avisynth_c.h:553
int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:324
static void smc_decode_stream(SmcContext *s)
Definition: smc.c:80
uint8_t pixel
Definition: tiny_ssim.c:42
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:194
static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avpkt)
Definition: ccaption_dec.c:722
#define COLORS_PER_TABLE
Definition: smc.c:44
GLint GLenum GLboolean GLsizei stride
Definition: opengl_enc.c:105
common internal api header.
if(ret< 0)
Definition: vf_mcdeint.c:282
void * priv_data
Definition: avcodec.h:1684
int pixels
Definition: avisynth_c.h:298
#define GET_BLOCK_COUNT()
Definition: smc.c:61
uint8_t * av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type, int *size)
Get side information from packet.
Definition: avpacket.c:320
#define height
This structure stores compressed data.
Definition: avcodec.h:1554
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:953