FFmpeg
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  if (bytestream2_get_bytes_left(&s->gb) < 1) {
136  av_log(s->avctx, AV_LOG_ERROR, "input too small\n");
137  return;
138  }
139 
140  opcode = bytestream2_get_byte(&s->gb);
141  switch (opcode & 0xF0) {
142  /* skip n blocks */
143  case 0x00:
144  case 0x10:
145  n_blocks = GET_BLOCK_COUNT();
146  while (n_blocks--) {
147  ADVANCE_BLOCK();
148  }
149  break;
150 
151  /* repeat last block n times */
152  case 0x20:
153  case 0x30:
154  n_blocks = GET_BLOCK_COUNT();
155 
156  /* sanity check */
157  if ((row_ptr == 0) && (pixel_ptr == 0)) {
158  av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but no blocks rendered yet\n",
159  opcode & 0xF0);
160  return;
161  }
162 
163  /* figure out where the previous block started */
164  if (pixel_ptr == 0)
165  prev_block_ptr1 =
166  (row_ptr - s->avctx->width * 4) + s->avctx->width - 4;
167  else
168  prev_block_ptr1 = row_ptr + pixel_ptr - 4;
169 
170  while (n_blocks--) {
171  block_ptr = row_ptr + pixel_ptr;
172  prev_block_ptr = prev_block_ptr1;
173  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
174  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
175  pixels[block_ptr++] = pixels[prev_block_ptr++];
176  }
177  block_ptr += row_inc;
178  prev_block_ptr += row_inc;
179  }
180  ADVANCE_BLOCK();
181  }
182  break;
183 
184  /* repeat previous pair of blocks n times */
185  case 0x40:
186  case 0x50:
187  n_blocks = GET_BLOCK_COUNT();
188  n_blocks *= 2;
189 
190  /* sanity check */
191  if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) {
192  av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n",
193  opcode & 0xF0);
194  return;
195  }
196 
197  /* figure out where the previous 2 blocks started */
198  if (pixel_ptr == 0)
199  prev_block_ptr1 = (row_ptr - s->avctx->width * 4) +
200  s->avctx->width - 4 * 2;
201  else if (pixel_ptr == 4)
202  prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc;
203  else
204  prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2;
205 
206  if (pixel_ptr == 0)
207  prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc;
208  else
209  prev_block_ptr2 = row_ptr + pixel_ptr - 4;
210 
211  prev_block_flag = 0;
212  while (n_blocks--) {
213  block_ptr = row_ptr + pixel_ptr;
214  if (prev_block_flag)
215  prev_block_ptr = prev_block_ptr2;
216  else
217  prev_block_ptr = prev_block_ptr1;
218  prev_block_flag = !prev_block_flag;
219 
220  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
221  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
222  pixels[block_ptr++] = pixels[prev_block_ptr++];
223  }
224  block_ptr += row_inc;
225  prev_block_ptr += row_inc;
226  }
227  ADVANCE_BLOCK();
228  }
229  break;
230 
231  /* 1-color block encoding */
232  case 0x60:
233  case 0x70:
234  n_blocks = GET_BLOCK_COUNT();
235  pixel = bytestream2_get_byte(&s->gb);
236 
237  while (n_blocks--) {
238  block_ptr = row_ptr + pixel_ptr;
239  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
240  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
241  pixels[block_ptr++] = pixel;
242  }
243  block_ptr += row_inc;
244  }
245  ADVANCE_BLOCK();
246  }
247  break;
248 
249  /* 2-color block encoding */
250  case 0x80:
251  case 0x90:
252  n_blocks = (opcode & 0x0F) + 1;
253 
254  /* figure out which color pair to use to paint the 2-color block */
255  if ((opcode & 0xF0) == 0x80) {
256  /* fetch the next 2 colors from bytestream and store in next
257  * available entry in the color pair table */
258  for (i = 0; i < CPAIR; i++) {
259  pixel = bytestream2_get_byte(&s->gb);
260  color_table_index = CPAIR * color_pair_index + i;
261  s->color_pairs[color_table_index] = pixel;
262  }
263  /* this is the base index to use for this block */
264  color_table_index = CPAIR * color_pair_index;
265  color_pair_index++;
266  /* wraparound */
267  if (color_pair_index == COLORS_PER_TABLE)
268  color_pair_index = 0;
269  } else
270  color_table_index = CPAIR * bytestream2_get_byte(&s->gb);
271 
272  while (n_blocks--) {
273  color_flags = bytestream2_get_be16(&s->gb);
274  flag_mask = 0x8000;
275  block_ptr = row_ptr + pixel_ptr;
276  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
277  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
278  if (color_flags & flag_mask)
279  pixel = color_table_index + 1;
280  else
281  pixel = color_table_index;
282  flag_mask >>= 1;
283  pixels[block_ptr++] = s->color_pairs[pixel];
284  }
285  block_ptr += row_inc;
286  }
287  ADVANCE_BLOCK();
288  }
289  break;
290 
291  /* 4-color block encoding */
292  case 0xA0:
293  case 0xB0:
294  n_blocks = (opcode & 0x0F) + 1;
295 
296  /* figure out which color quad to use to paint the 4-color block */
297  if ((opcode & 0xF0) == 0xA0) {
298  /* fetch the next 4 colors from bytestream and store in next
299  * available entry in the color quad table */
300  for (i = 0; i < CQUAD; i++) {
301  pixel = bytestream2_get_byte(&s->gb);
302  color_table_index = CQUAD * color_quad_index + i;
303  s->color_quads[color_table_index] = pixel;
304  }
305  /* this is the base index to use for this block */
306  color_table_index = CQUAD * color_quad_index;
307  color_quad_index++;
308  /* wraparound */
309  if (color_quad_index == COLORS_PER_TABLE)
310  color_quad_index = 0;
311  } else
312  color_table_index = CQUAD * bytestream2_get_byte(&s->gb);
313 
314  while (n_blocks--) {
315  color_flags = bytestream2_get_be32(&s->gb);
316  /* flag mask actually acts as a bit shift count here */
317  flag_mask = 30;
318  block_ptr = row_ptr + pixel_ptr;
319  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
320  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
321  pixel = color_table_index +
322  ((color_flags >> flag_mask) & 0x03);
323  flag_mask -= 2;
324  pixels[block_ptr++] = s->color_quads[pixel];
325  }
326  block_ptr += row_inc;
327  }
328  ADVANCE_BLOCK();
329  }
330  break;
331 
332  /* 8-color block encoding */
333  case 0xC0:
334  case 0xD0:
335  n_blocks = (opcode & 0x0F) + 1;
336 
337  /* figure out which color octet to use to paint the 8-color block */
338  if ((opcode & 0xF0) == 0xC0) {
339  /* fetch the next 8 colors from bytestream and store in next
340  * available entry in the color octet table */
341  for (i = 0; i < COCTET; i++) {
342  pixel = bytestream2_get_byte(&s->gb);
343  color_table_index = COCTET * color_octet_index + i;
344  s->color_octets[color_table_index] = pixel;
345  }
346  /* this is the base index to use for this block */
347  color_table_index = COCTET * color_octet_index;
348  color_octet_index++;
349  /* wraparound */
350  if (color_octet_index == COLORS_PER_TABLE)
351  color_octet_index = 0;
352  } else
353  color_table_index = COCTET * bytestream2_get_byte(&s->gb);
354 
355  while (n_blocks--) {
356  /*
357  For this input of 6 hex bytes:
358  01 23 45 67 89 AB
359  Mangle it to this output:
360  flags_a = xx012456, flags_b = xx89A37B
361  */
362  /* build the color flags */
363  int val1 = bytestream2_get_be16(&s->gb);
364  int val2 = bytestream2_get_be16(&s->gb);
365  int val3 = bytestream2_get_be16(&s->gb);
366  color_flags_a = ((val1 & 0xFFF0) << 8) | (val2 >> 4);
367  color_flags_b = ((val3 & 0xFFF0) << 8) |
368  ((val1 & 0x0F) << 8) | ((val2 & 0x0F) << 4) | (val3 & 0x0F);
369 
370  color_flags = color_flags_a;
371  /* flag mask actually acts as a bit shift count here */
372  flag_mask = 21;
373  block_ptr = row_ptr + pixel_ptr;
374  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
375  /* reload flags at third row (iteration pixel_y == 2) */
376  if (pixel_y == 2) {
377  color_flags = color_flags_b;
378  flag_mask = 21;
379  }
380  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
381  pixel = color_table_index +
382  ((color_flags >> flag_mask) & 0x07);
383  flag_mask -= 3;
384  pixels[block_ptr++] = s->color_octets[pixel];
385  }
386  block_ptr += row_inc;
387  }
388  ADVANCE_BLOCK();
389  }
390  break;
391 
392  /* 16-color block encoding (every pixel is a different color) */
393  case 0xE0:
394  n_blocks = (opcode & 0x0F) + 1;
395 
396  while (n_blocks--) {
397  block_ptr = row_ptr + pixel_ptr;
398  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
399  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
400  pixels[block_ptr++] = bytestream2_get_byte(&s->gb);
401  }
402  block_ptr += row_inc;
403  }
404  ADVANCE_BLOCK();
405  }
406  break;
407 
408  case 0xF0:
409  avpriv_request_sample(s->avctx, "0xF0 opcode");
410  break;
411  }
412  }
413 
414  return;
415 }
416 
418 {
419  SmcContext *s = avctx->priv_data;
420 
421  s->avctx = avctx;
422  avctx->pix_fmt = AV_PIX_FMT_PAL8;
423 
424  s->frame = av_frame_alloc();
425  if (!s->frame)
426  return AVERROR(ENOMEM);
427 
428  return 0;
429 }
430 
432  void *data, int *got_frame,
433  AVPacket *avpkt)
434 {
435  const uint8_t *buf = avpkt->data;
436  int buf_size = avpkt->size;
437  SmcContext *s = avctx->priv_data;
438  buffer_size_t pal_size;
439  const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &pal_size);
440  int ret;
441  int total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
442 
443  if (total_blocks / 1024 > avpkt->size)
444  return AVERROR_INVALIDDATA;
445 
446  bytestream2_init(&s->gb, buf, buf_size);
447 
448  if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
449  return ret;
450 
451  if (pal && pal_size == AVPALETTE_SIZE) {
452  s->frame->palette_has_changed = 1;
453  memcpy(s->pal, pal, AVPALETTE_SIZE);
454  } else if (pal) {
455  av_log(avctx, AV_LOG_ERROR, "Palette size %d is wrong\n", pal_size);
456  }
457 
459 
460  *got_frame = 1;
461  if ((ret = av_frame_ref(data, s->frame)) < 0)
462  return ret;
463 
464  /* always report that the buffer was completely consumed */
465  return buf_size;
466 }
467 
469 {
470  SmcContext *s = avctx->priv_data;
471 
472  av_frame_free(&s->frame);
473 
474  return 0;
475 }
476 
478  .name = "smc",
479  .long_name = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"),
480  .type = AVMEDIA_TYPE_VIDEO,
481  .id = AV_CODEC_ID_SMC,
482  .priv_data_size = sizeof(SmcContext),
484  .close = smc_decode_end,
486  .capabilities = AV_CODEC_CAP_DR1,
487  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
488 };
AVCodec
AVCodec.
Definition: codec.h:197
stride
int stride
Definition: mace.c:144
FF_CODEC_CAP_INIT_THREADSAFE
#define FF_CODEC_CAP_INIT_THREADSAFE
The codec does not modify any global variables in the init function, allowing to call the init functi...
Definition: internal.h:41
init
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:31
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
av_packet_get_side_data
uint8_t * av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type, buffer_size_t *size)
Definition: avpacket.c:368
SmcContext
Definition: smc.c:46
GET_BLOCK_COUNT
#define GET_BLOCK_COUNT()
Definition: smc.c:61
GetByteContext
Definition: bytestream.h:33
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:318
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:369
AV_PKT_DATA_PALETTE
@ AV_PKT_DATA_PALETTE
An AV_PKT_DATA_PALETTE side data packet contains exactly AVPALETTE_SIZE bytes worth of palette.
Definition: packet.h:46
data
const char data[16]
Definition: mxf.c:142
SmcContext::color_quads
unsigned char color_quads[COLORS_PER_TABLE *CQUAD]
Definition: smc.c:55
SmcContext::frame
AVFrame * frame
Definition: smc.c:49
SmcContext::color_pairs
unsigned char color_pairs[COLORS_PER_TABLE *CPAIR]
Definition: smc.c:54
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:168
SmcContext::pal
uint32_t pal[256]
Definition: smc.c:58
smc_decode_init
static av_cold int smc_decode_init(AVCodecContext *avctx)
Definition: smc.c:417
AV_CODEC_ID_SMC
@ AV_CODEC_ID_SMC
Definition: codec_id.h:98
ADVANCE_BLOCK
#define ADVANCE_BLOCK()
Definition: smc.c:64
smc_decode_frame
static int smc_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: smc.c:431
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:190
SmcContext::avctx
AVCodecContext * avctx
Definition: smc.c:48
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
av_cold
#define av_cold
Definition: attributes.h:90
decode
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:71
width
#define width
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:257
buffer_size_t
int buffer_size_t
Definition: internal.h:306
CPAIR
#define CPAIR
Definition: smc.c:40
CQUAD
#define CQUAD
Definition: smc.c:41
if
if(ret)
Definition: filter_design.txt:179
pixel
uint8_t pixel
Definition: tiny_ssim.c:42
AVPALETTE_SIZE
#define AVPALETTE_SIZE
Definition: pixfmt.h:32
bytestream2_get_bytes_left
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:158
SmcContext::gb
GetByteContext gb
Definition: smc.c:51
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:52
AVPacket::size
int size
Definition: packet.h:370
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
bytestream2_size
static av_always_inline int bytestream2_size(GetByteContext *g)
Definition: bytestream.h:202
av_frame_ref
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:443
ff_smc_decoder
AVCodec ff_smc_decoder
Definition: smc.c:477
height
#define height
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:205
i
int i
Definition: input.c:407
SmcContext::color_octets
unsigned char color_octets[COLORS_PER_TABLE *COCTET]
Definition: smc.c:56
uint8_t
uint8_t
Definition: audio_convert.c:194
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:204
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:746
avcodec.h
AV_PIX_FMT_PAL8
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
ff_reget_buffer
int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Identical in function to ff_get_buffer(), except it reuses the existing buffer if available.
Definition: decode.c:2007
ret
ret
Definition: filter_design.txt:187
smc_decode_stream
static void smc_decode_stream(SmcContext *s)
Definition: smc.c:80
AVCodecContext
main external API structure.
Definition: avcodec.h:536
COCTET
#define COCTET
Definition: smc.c:42
COLORS_PER_TABLE
#define COLORS_PER_TABLE
Definition: smc.c:44
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
avpriv_request_sample
#define avpriv_request_sample(...)
Definition: tableprint_vlc.h:39
AVPacket
This structure stores compressed data.
Definition: packet.h:346
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:563
bytestream.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
smc_decode_end
static av_cold int smc_decode_end(AVCodecContext *avctx)
Definition: smc.c:468