FFmpeg
 All Data Structures 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 
39 #define CPAIR 2
40 #define CQUAD 4
41 #define COCTET 8
42 
43 #define COLORS_PER_TABLE 256
44 
45 typedef struct SmcContext {
46 
49 
51 
52  /* SMC color tables */
56 
57  uint32_t pal[256];
58 } SmcContext;
59 
60 #define GET_BLOCK_COUNT() \
61  (opcode & 0x10) ? (1 + bytestream2_get_byte(&s->gb)) : 1 + (opcode & 0x0F);
62 
63 #define ADVANCE_BLOCK() \
64 { \
65  pixel_ptr += 4; \
66  if (pixel_ptr >= width) \
67  { \
68  pixel_ptr = 0; \
69  row_ptr += stride * 4; \
70  } \
71  total_blocks--; \
72  if (total_blocks < 0) \
73  { \
74  av_log(s->avctx, AV_LOG_INFO, "warning: block counter just went negative (this should not happen)\n"); \
75  return; \
76  } \
77 }
78 
80 {
81  int width = s->avctx->width;
82  int height = s->avctx->height;
83  int stride = s->frame.linesize[0];
84  int i;
85  int chunk_size;
86  int buf_size = bytestream2_size(&s->gb);
87  unsigned char opcode;
88  int n_blocks;
89  unsigned int color_flags;
90  unsigned int color_flags_a;
91  unsigned int color_flags_b;
92  unsigned int flag_mask;
93 
94  unsigned char *pixels = s->frame.data[0];
95 
96  int image_size = height * s->frame.linesize[0];
97  int row_ptr = 0;
98  int pixel_ptr = 0;
99  int pixel_x, pixel_y;
100  int row_inc = stride - 4;
101  int block_ptr;
102  int prev_block_ptr;
103  int prev_block_ptr1, prev_block_ptr2;
104  int prev_block_flag;
105  int total_blocks;
106  int color_table_index; /* indexes to color pair, quad, or octet tables */
107  int pixel;
108 
109  int color_pair_index = 0;
110  int color_quad_index = 0;
111  int color_octet_index = 0;
112 
113  /* make the palette available */
114  memcpy(s->frame.data[1], s->pal, AVPALETTE_SIZE);
115 
116  bytestream2_skip(&s->gb, 1);
117  chunk_size = bytestream2_get_be24(&s->gb);
118  if (chunk_size != buf_size)
119  av_log(s->avctx, AV_LOG_INFO, "warning: MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n",
120  chunk_size, buf_size);
121 
122  chunk_size = buf_size;
123  total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
124 
125  /* traverse through the blocks */
126  while (total_blocks) {
127  /* sanity checks */
128  /* make sure the row pointer hasn't gone wild */
129  if (row_ptr >= image_size) {
130  av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (row ptr = %d, height = %d)\n",
131  row_ptr, image_size);
132  return;
133  }
134 
135  opcode = bytestream2_get_byte(&s->gb);
136  switch (opcode & 0xF0) {
137  /* skip n blocks */
138  case 0x00:
139  case 0x10:
140  n_blocks = GET_BLOCK_COUNT();
141  while (n_blocks--) {
142  ADVANCE_BLOCK();
143  }
144  break;
145 
146  /* repeat last block n times */
147  case 0x20:
148  case 0x30:
149  n_blocks = GET_BLOCK_COUNT();
150 
151  /* sanity check */
152  if ((row_ptr == 0) && (pixel_ptr == 0)) {
153  av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but no blocks rendered yet\n",
154  opcode & 0xF0);
155  return;
156  }
157 
158  /* figure out where the previous block started */
159  if (pixel_ptr == 0)
160  prev_block_ptr1 =
161  (row_ptr - s->avctx->width * 4) + s->avctx->width - 4;
162  else
163  prev_block_ptr1 = row_ptr + pixel_ptr - 4;
164 
165  while (n_blocks--) {
166  block_ptr = row_ptr + pixel_ptr;
167  prev_block_ptr = prev_block_ptr1;
168  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
169  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
170  pixels[block_ptr++] = pixels[prev_block_ptr++];
171  }
172  block_ptr += row_inc;
173  prev_block_ptr += row_inc;
174  }
175  ADVANCE_BLOCK();
176  }
177  break;
178 
179  /* repeat previous pair of blocks n times */
180  case 0x40:
181  case 0x50:
182  n_blocks = GET_BLOCK_COUNT();
183  n_blocks *= 2;
184 
185  /* sanity check */
186  if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) {
187  av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n",
188  opcode & 0xF0);
189  return;
190  }
191 
192  /* figure out where the previous 2 blocks started */
193  if (pixel_ptr == 0)
194  prev_block_ptr1 = (row_ptr - s->avctx->width * 4) +
195  s->avctx->width - 4 * 2;
196  else if (pixel_ptr == 4)
197  prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc;
198  else
199  prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2;
200 
201  if (pixel_ptr == 0)
202  prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc;
203  else
204  prev_block_ptr2 = row_ptr + pixel_ptr - 4;
205 
206  prev_block_flag = 0;
207  while (n_blocks--) {
208  block_ptr = row_ptr + pixel_ptr;
209  if (prev_block_flag)
210  prev_block_ptr = prev_block_ptr2;
211  else
212  prev_block_ptr = prev_block_ptr1;
213  prev_block_flag = !prev_block_flag;
214 
215  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
216  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
217  pixels[block_ptr++] = pixels[prev_block_ptr++];
218  }
219  block_ptr += row_inc;
220  prev_block_ptr += row_inc;
221  }
222  ADVANCE_BLOCK();
223  }
224  break;
225 
226  /* 1-color block encoding */
227  case 0x60:
228  case 0x70:
229  n_blocks = GET_BLOCK_COUNT();
230  pixel = bytestream2_get_byte(&s->gb);
231 
232  while (n_blocks--) {
233  block_ptr = row_ptr + pixel_ptr;
234  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
235  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
236  pixels[block_ptr++] = pixel;
237  }
238  block_ptr += row_inc;
239  }
240  ADVANCE_BLOCK();
241  }
242  break;
243 
244  /* 2-color block encoding */
245  case 0x80:
246  case 0x90:
247  n_blocks = (opcode & 0x0F) + 1;
248 
249  /* figure out which color pair to use to paint the 2-color block */
250  if ((opcode & 0xF0) == 0x80) {
251  /* fetch the next 2 colors from bytestream and store in next
252  * available entry in the color pair table */
253  for (i = 0; i < CPAIR; i++) {
254  pixel = bytestream2_get_byte(&s->gb);
255  color_table_index = CPAIR * color_pair_index + i;
256  s->color_pairs[color_table_index] = pixel;
257  }
258  /* this is the base index to use for this block */
259  color_table_index = CPAIR * color_pair_index;
260  color_pair_index++;
261  /* wraparound */
262  if (color_pair_index == COLORS_PER_TABLE)
263  color_pair_index = 0;
264  } else
265  color_table_index = CPAIR * bytestream2_get_byte(&s->gb);
266 
267  while (n_blocks--) {
268  color_flags = bytestream2_get_be16(&s->gb);
269  flag_mask = 0x8000;
270  block_ptr = row_ptr + pixel_ptr;
271  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
272  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
273  if (color_flags & flag_mask)
274  pixel = color_table_index + 1;
275  else
276  pixel = color_table_index;
277  flag_mask >>= 1;
278  pixels[block_ptr++] = s->color_pairs[pixel];
279  }
280  block_ptr += row_inc;
281  }
282  ADVANCE_BLOCK();
283  }
284  break;
285 
286  /* 4-color block encoding */
287  case 0xA0:
288  case 0xB0:
289  n_blocks = (opcode & 0x0F) + 1;
290 
291  /* figure out which color quad to use to paint the 4-color block */
292  if ((opcode & 0xF0) == 0xA0) {
293  /* fetch the next 4 colors from bytestream and store in next
294  * available entry in the color quad table */
295  for (i = 0; i < CQUAD; i++) {
296  pixel = bytestream2_get_byte(&s->gb);
297  color_table_index = CQUAD * color_quad_index + i;
298  s->color_quads[color_table_index] = pixel;
299  }
300  /* this is the base index to use for this block */
301  color_table_index = CQUAD * color_quad_index;
302  color_quad_index++;
303  /* wraparound */
304  if (color_quad_index == COLORS_PER_TABLE)
305  color_quad_index = 0;
306  } else
307  color_table_index = CQUAD * bytestream2_get_byte(&s->gb);
308 
309  while (n_blocks--) {
310  color_flags = bytestream2_get_be32(&s->gb);
311  /* flag mask actually acts as a bit shift count here */
312  flag_mask = 30;
313  block_ptr = row_ptr + pixel_ptr;
314  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
315  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
316  pixel = color_table_index +
317  ((color_flags >> flag_mask) & 0x03);
318  flag_mask -= 2;
319  pixels[block_ptr++] = s->color_quads[pixel];
320  }
321  block_ptr += row_inc;
322  }
323  ADVANCE_BLOCK();
324  }
325  break;
326 
327  /* 8-color block encoding */
328  case 0xC0:
329  case 0xD0:
330  n_blocks = (opcode & 0x0F) + 1;
331 
332  /* figure out which color octet to use to paint the 8-color block */
333  if ((opcode & 0xF0) == 0xC0) {
334  /* fetch the next 8 colors from bytestream and store in next
335  * available entry in the color octet table */
336  for (i = 0; i < COCTET; i++) {
337  pixel = bytestream2_get_byte(&s->gb);
338  color_table_index = COCTET * color_octet_index + i;
339  s->color_octets[color_table_index] = pixel;
340  }
341  /* this is the base index to use for this block */
342  color_table_index = COCTET * color_octet_index;
343  color_octet_index++;
344  /* wraparound */
345  if (color_octet_index == COLORS_PER_TABLE)
346  color_octet_index = 0;
347  } else
348  color_table_index = COCTET * bytestream2_get_byte(&s->gb);
349 
350  while (n_blocks--) {
351  /*
352  For this input of 6 hex bytes:
353  01 23 45 67 89 AB
354  Mangle it to this output:
355  flags_a = xx012456, flags_b = xx89A37B
356  */
357  /* build the color flags */
358  int val1 = bytestream2_get_be16(&s->gb);
359  int val2 = bytestream2_get_be16(&s->gb);
360  int val3 = bytestream2_get_be16(&s->gb);
361  color_flags_a = ((val1 & 0xFFF0) << 8) | (val2 >> 4);
362  color_flags_b = ((val3 & 0xFFF0) << 8) |
363  ((val1 & 0x0F) << 8) | ((val2 & 0x0F) << 4) | (val3 & 0x0F);
364 
365  color_flags = color_flags_a;
366  /* flag mask actually acts as a bit shift count here */
367  flag_mask = 21;
368  block_ptr = row_ptr + pixel_ptr;
369  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
370  /* reload flags at third row (iteration pixel_y == 2) */
371  if (pixel_y == 2) {
372  color_flags = color_flags_b;
373  flag_mask = 21;
374  }
375  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
376  pixel = color_table_index +
377  ((color_flags >> flag_mask) & 0x07);
378  flag_mask -= 3;
379  pixels[block_ptr++] = s->color_octets[pixel];
380  }
381  block_ptr += row_inc;
382  }
383  ADVANCE_BLOCK();
384  }
385  break;
386 
387  /* 16-color block encoding (every pixel is a different color) */
388  case 0xE0:
389  n_blocks = (opcode & 0x0F) + 1;
390 
391  while (n_blocks--) {
392  block_ptr = row_ptr + pixel_ptr;
393  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
394  for (pixel_x = 0; pixel_x < 4; pixel_x++) {
395  pixels[block_ptr++] = bytestream2_get_byte(&s->gb);
396  }
397  block_ptr += row_inc;
398  }
399  ADVANCE_BLOCK();
400  }
401  break;
402 
403  case 0xF0:
404  av_log_missing_feature(s->avctx, "0xF0 opcode", 1);
405  break;
406  }
407  }
408 
409  return;
410 }
411 
413 {
414  SmcContext *s = avctx->priv_data;
415 
416  s->avctx = avctx;
417  avctx->pix_fmt = AV_PIX_FMT_PAL8;
418 
420  s->frame.data[0] = NULL;
421 
422  return 0;
423 }
424 
426  void *data, int *got_frame,
427  AVPacket *avpkt)
428 {
429  const uint8_t *buf = avpkt->data;
430  int buf_size = avpkt->size;
431  SmcContext *s = avctx->priv_data;
433 
434  bytestream2_init(&s->gb, buf, buf_size);
435 
436  s->frame.reference = 3;
439  if (avctx->reget_buffer(avctx, &s->frame)) {
440  av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
441  return -1;
442  }
443 
444  if (pal) {
445  s->frame.palette_has_changed = 1;
446  memcpy(s->pal, pal, AVPALETTE_SIZE);
447  }
448 
450 
451  *got_frame = 1;
452  *(AVFrame*)data = s->frame;
453 
454  /* always report that the buffer was completely consumed */
455  return buf_size;
456 }
457 
459 {
460  SmcContext *s = avctx->priv_data;
461 
462  if (s->frame.data[0])
463  avctx->release_buffer(avctx, &s->frame);
464 
465  return 0;
466 }
467 
469  .name = "smc",
470  .type = AVMEDIA_TYPE_VIDEO,
471  .id = AV_CODEC_ID_SMC,
472  .priv_data_size = sizeof(SmcContext),
476  .capabilities = CODEC_CAP_DR1,
477  .long_name = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"),
478 };