FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sanm.c
Go to the documentation of this file.
1 /*
2  * LucasArts Smush video decoder
3  * Copyright (c) 2006 Cyril Zorin
4  * Copyright (c) 2011 Konstantin Shishkov
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 // #define DEBUG 1
24 
25 #include "avcodec.h"
26 #include "copy_block.h"
27 #include "bytestream.h"
28 #include "internal.h"
29 #include "libavutil/bswap.h"
30 #include "libavutil/imgutils.h"
31 #include "sanm_data.h"
32 #include "libavutil/avassert.h"
33 
34 #define NGLYPHS 256
35 
36 typedef struct {
39 
40  int version, subversion;
41  uint32_t pal[256];
42  int16_t delta_pal[768];
43 
44  int pitch;
45  int width, height;
46  int aligned_width, aligned_height;
47  int prev_seq;
48 
50  uint16_t *frm0, *frm1, *frm2;
52  uint32_t frm0_size, frm1_size, frm2_size;
54 
56  unsigned int rle_buf_size;
57 
59 
60  long npixels, buf_size;
61 
62  uint16_t codebook[256];
63  uint16_t small_codebook[4];
64 
65  int8_t p4x4glyphs[NGLYPHS][16];
66  int8_t p8x8glyphs[NGLYPHS][64];
68 
69 typedef struct {
70  int seq_num, codec, rotate_code, rle_output_size;
71 
72  uint16_t bg_color;
73  uint32_t width, height;
75 
76 enum GlyphEdge {
82 };
83 
84 enum GlyphDir {
90 };
91 
92 /**
93  * Return enum GlyphEdge of box where point (x, y) lies.
94  *
95  * @param x x point coordinate
96  * @param y y point coordinate
97  * @param edge_size box width/height.
98  */
99 static enum GlyphEdge which_edge(int x, int y, int edge_size)
100 {
101  const int edge_max = edge_size - 1;
102 
103  if (!y) {
104  return BOTTOM_EDGE;
105  } else if (y == edge_max) {
106  return TOP_EDGE;
107  } else if (!x) {
108  return LEFT_EDGE;
109  } else if (x == edge_max) {
110  return RIGHT_EDGE;
111  } else {
112  return NO_EDGE;
113  }
114 }
115 
116 static enum GlyphDir which_direction(enum GlyphEdge edge0, enum GlyphEdge edge1)
117 {
118  if ((edge0 == LEFT_EDGE && edge1 == RIGHT_EDGE) ||
119  (edge1 == LEFT_EDGE && edge0 == RIGHT_EDGE) ||
120  (edge0 == BOTTOM_EDGE && edge1 != TOP_EDGE) ||
121  (edge1 == BOTTOM_EDGE && edge0 != TOP_EDGE)) {
122  return DIR_UP;
123  } else if ((edge0 == TOP_EDGE && edge1 != BOTTOM_EDGE) ||
124  (edge1 == TOP_EDGE && edge0 != BOTTOM_EDGE)) {
125  return DIR_DOWN;
126  } else if ((edge0 == LEFT_EDGE && edge1 != RIGHT_EDGE) ||
127  (edge1 == LEFT_EDGE && edge0 != RIGHT_EDGE)) {
128  return DIR_LEFT;
129  } else if ((edge0 == TOP_EDGE && edge1 == BOTTOM_EDGE) ||
130  (edge1 == TOP_EDGE && edge0 == BOTTOM_EDGE) ||
131  (edge0 == RIGHT_EDGE && edge1 != LEFT_EDGE) ||
132  (edge1 == RIGHT_EDGE && edge0 != LEFT_EDGE)) {
133  return DIR_RIGHT;
134  }
135 
136  return NO_DIR;
137 }
138 
139 /**
140  * Interpolate two points.
141  */
142 static void interp_point(int8_t *points, int x0, int y0, int x1, int y1,
143  int pos, int npoints)
144 {
145  if (npoints) {
146  points[0] = (x0 * pos + x1 * (npoints - pos) + (npoints >> 1)) / npoints;
147  points[1] = (y0 * pos + y1 * (npoints - pos) + (npoints >> 1)) / npoints;
148  } else {
149  points[0] = x0;
150  points[1] = y0;
151  }
152 }
153 
154 /**
155  * Construct glyphs by iterating through vectors coordinates.
156  *
157  * @param pglyphs pointer to table where glyphs are stored
158  * @param xvec pointer to x component of vectors coordinates
159  * @param yvec pointer to y component of vectors coordinates
160  * @param side_length glyph width/height.
161  */
162 static void make_glyphs(int8_t *pglyphs, const int8_t *xvec, const int8_t *yvec,
163  const int side_length)
164 {
165  const int glyph_size = side_length * side_length;
166  int8_t *pglyph = pglyphs;
167 
168  int i, j;
169  for (i = 0; i < GLYPH_COORD_VECT_SIZE; i++) {
170  int x0 = xvec[i];
171  int y0 = yvec[i];
172  enum GlyphEdge edge0 = which_edge(x0, y0, side_length);
173 
174  for (j = 0; j < GLYPH_COORD_VECT_SIZE; j++, pglyph += glyph_size) {
175  int x1 = xvec[j];
176  int y1 = yvec[j];
177  enum GlyphEdge edge1 = which_edge(x1, y1, side_length);
178  enum GlyphDir dir = which_direction(edge0, edge1);
179  int npoints = FFMAX(FFABS(x1 - x0), FFABS(y1 - y0));
180  int ipoint;
181 
182  for (ipoint = 0; ipoint <= npoints; ipoint++) {
183  int8_t point[2];
184  int irow, icol;
185 
186  interp_point(point, x0, y0, x1, y1, ipoint, npoints);
187 
188  switch (dir) {
189  case DIR_UP:
190  for (irow = point[1]; irow >= 0; irow--)
191  pglyph[point[0] + irow * side_length] = 1;
192  break;
193 
194  case DIR_DOWN:
195  for (irow = point[1]; irow < side_length; irow++)
196  pglyph[point[0] + irow * side_length] = 1;
197  break;
198 
199  case DIR_LEFT:
200  for (icol = point[0]; icol >= 0; icol--)
201  pglyph[icol + point[1] * side_length] = 1;
202  break;
203 
204  case DIR_RIGHT:
205  for (icol = point[0]; icol < side_length; icol++)
206  pglyph[icol + point[1] * side_length] = 1;
207  break;
208  }
209  }
210  }
211  }
212 }
213 
214 static void init_sizes(SANMVideoContext *ctx, int width, int height)
215 {
216  ctx->width = width;
217  ctx->height = height;
218  ctx->npixels = width * height;
219 
220  ctx->aligned_width = FFALIGN(width, 8);
221  ctx->aligned_height = FFALIGN(height, 8);
222 
223  ctx->buf_size = ctx->aligned_width * ctx->aligned_height * sizeof(ctx->frm0[0]);
224  ctx->pitch = width;
225 }
226 
228 {
229  av_freep(&ctx->frm0);
230  av_freep(&ctx->frm1);
231  av_freep(&ctx->frm2);
232  av_freep(&ctx->stored_frame);
233  av_freep(&ctx->rle_buf);
234  ctx->frm0_size =
235  ctx->frm1_size =
236  ctx->frm2_size = 0;
237 }
238 
240 {
241  av_fast_padded_malloc(&ctx->frm0, &ctx->frm0_size, ctx->buf_size);
242  av_fast_padded_malloc(&ctx->frm1, &ctx->frm1_size, ctx->buf_size);
243  av_fast_padded_malloc(&ctx->frm2, &ctx->frm2_size, ctx->buf_size);
244  if (!ctx->version)
246 
247  if (!ctx->frm0 || !ctx->frm1 || !ctx->frm2 || (!ctx->stored_frame && !ctx->version)) {
248  destroy_buffers(ctx);
249  return AVERROR(ENOMEM);
250  }
251 
252  return 0;
253 }
254 
255 static void rotate_bufs(SANMVideoContext *ctx, int rotate_code)
256 {
257  av_dlog(ctx->avctx, "rotate %d\n", rotate_code);
258  if (rotate_code == 2)
259  FFSWAP(uint16_t*, ctx->frm1, ctx->frm2);
260  FFSWAP(uint16_t*, ctx->frm2, ctx->frm0);
261 }
262 
264 {
265  SANMVideoContext *ctx = avctx->priv_data;
266 
267  ctx->avctx = avctx;
268  ctx->version = !avctx->extradata_size;
269 
271 
272  init_sizes(ctx, avctx->width, avctx->height);
273  if (init_buffers(ctx)) {
274  av_log(avctx, AV_LOG_ERROR, "error allocating buffers\n");
275  return AVERROR(ENOMEM);
276  }
277 
278  make_glyphs(ctx->p4x4glyphs[0], glyph4_x, glyph4_y, 4);
279  make_glyphs(ctx->p8x8glyphs[0], glyph8_x, glyph8_y, 8);
280 
281  if (!ctx->version) {
282  int i;
283 
284  if (avctx->extradata_size < 1026) {
285  av_log(avctx, AV_LOG_ERROR, "not enough extradata\n");
286  return AVERROR_INVALIDDATA;
287  }
288 
289  ctx->subversion = AV_RL16(avctx->extradata);
290  for (i = 0; i < 256; i++)
291  ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4);
292  }
293 
294  return 0;
295 }
296 
298 {
299  SANMVideoContext *ctx = avctx->priv_data;
300 
301  destroy_buffers(ctx);
302 
303  return 0;
304 }
305 
306 static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
307 {
308  int opcode, color, run_len, left = out_size;
309 
310  while (left > 0) {
311  opcode = bytestream2_get_byte(&ctx->gb);
312  run_len = (opcode >> 1) + 1;
313  if (run_len > left || bytestream2_get_bytes_left(&ctx->gb) <= 0)
314  return AVERROR_INVALIDDATA;
315 
316  if (opcode & 1) {
317  color = bytestream2_get_byte(&ctx->gb);
318  memset(dst, color, run_len);
319  } else {
320  if (bytestream2_get_bytes_left(&ctx->gb) < run_len)
321  return AVERROR_INVALIDDATA;
322  bytestream2_get_bufferu(&ctx->gb, dst, run_len);
323  }
324 
325  dst += run_len;
326  left -= run_len;
327  }
328 
329  return 0;
330 }
331 
332 static int old_codec1(SANMVideoContext *ctx, int top,
333  int left, int width, int height)
334 {
335  uint8_t *dst = ((uint8_t*)ctx->frm0) + left + top * ctx->pitch;
336  int i, j, len, flag, code, val, pos, end;
337 
338  for (i = 0; i < height; i++) {
339  pos = 0;
340 
341  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
342  return AVERROR_INVALIDDATA;
343 
344  len = bytestream2_get_le16u(&ctx->gb);
345  end = bytestream2_tell(&ctx->gb) + len;
346 
347  while (bytestream2_tell(&ctx->gb) < end) {
348  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
349  return AVERROR_INVALIDDATA;
350 
351  code = bytestream2_get_byteu(&ctx->gb);
352  flag = code & 1;
353  code = (code >> 1) + 1;
354  if (pos + code > width)
355  return AVERROR_INVALIDDATA;
356  if (flag) {
357  val = bytestream2_get_byteu(&ctx->gb);
358  if (val)
359  memset(dst + pos, val, code);
360  pos += code;
361  } else {
362  if (bytestream2_get_bytes_left(&ctx->gb) < code)
363  return AVERROR_INVALIDDATA;
364  for (j = 0; j < code; j++) {
365  val = bytestream2_get_byteu(&ctx->gb);
366  if (val)
367  dst[pos] = val;
368  pos++;
369  }
370  }
371  }
372  dst += ctx->pitch;
373  }
374  ctx->rotate_code = 0;
375 
376  return 0;
377 }
378 
379 static inline void codec37_mv(uint8_t *dst, const uint8_t *src,
380  int height, int stride, int x, int y)
381 {
382  int pos, i, j;
383 
384  pos = x + y * stride;
385  for (j = 0; j < 4; j++) {
386  for (i = 0; i < 4; i++) {
387  if ((pos + i) < 0 || (pos + i) >= height * stride)
388  dst[i] = 0;
389  else
390  dst[i] = src[i];
391  }
392  dst += stride;
393  src += stride;
394  pos += stride;
395  }
396 }
397 
398 static int old_codec37(SANMVideoContext *ctx, int top,
399  int left, int width, int height)
400 {
401  int stride = ctx->pitch;
402  int i, j, k, t;
403  int skip_run = 0;
404  int compr, mvoff, seq, flags;
405  uint32_t decoded_size;
406  uint8_t *dst, *prev;
407 
408  compr = bytestream2_get_byte(&ctx->gb);
409  mvoff = bytestream2_get_byte(&ctx->gb);
410  seq = bytestream2_get_le16(&ctx->gb);
411  decoded_size = bytestream2_get_le32(&ctx->gb);
412  bytestream2_skip(&ctx->gb, 4);
413  flags = bytestream2_get_byte(&ctx->gb);
414  bytestream2_skip(&ctx->gb, 3);
415 
416  if (decoded_size > ctx->height * stride - left - top * stride) {
417  decoded_size = ctx->height * stride - left - top * stride;
418  av_log(ctx->avctx, AV_LOG_WARNING, "decoded size is too large\n");
419  }
420 
421  ctx->rotate_code = 0;
422 
423  if (((seq & 1) || !(flags & 1)) && (compr && compr != 2))
424  rotate_bufs(ctx, 1);
425 
426  dst = ((uint8_t*)ctx->frm0) + left + top * stride;
427  prev = ((uint8_t*)ctx->frm2) + left + top * stride;
428 
429  if (mvoff > 2) {
430  av_log(ctx->avctx, AV_LOG_ERROR, "invalid motion base value %d\n", mvoff);
431  return AVERROR_INVALIDDATA;
432  }
433  av_dlog(ctx->avctx, "compression %d\n", compr);
434  switch (compr) {
435  case 0:
436  for (i = 0; i < height; i++) {
437  bytestream2_get_buffer(&ctx->gb, dst, width);
438  dst += stride;
439  }
440  memset(ctx->frm1, 0, ctx->height * stride);
441  memset(ctx->frm2, 0, ctx->height * stride);
442  break;
443  case 2:
444  if (rle_decode(ctx, dst, decoded_size))
445  return AVERROR_INVALIDDATA;
446  memset(ctx->frm1, 0, ctx->frm1_size);
447  memset(ctx->frm2, 0, ctx->frm2_size);
448  break;
449  case 3:
450  case 4:
451  if (flags & 4) {
452  for (j = 0; j < height; j += 4) {
453  for (i = 0; i < width; i += 4) {
454  int code;
455  if (skip_run) {
456  skip_run--;
457  copy_block4(dst + i, prev + i, stride, stride, 4);
458  continue;
459  }
460  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
461  return AVERROR_INVALIDDATA;
462  code = bytestream2_get_byteu(&ctx->gb);
463  switch (code) {
464  case 0xFF:
465  if (bytestream2_get_bytes_left(&ctx->gb) < 16)
466  return AVERROR_INVALIDDATA;
467  for (k = 0; k < 4; k++)
468  bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
469  break;
470  case 0xFE:
471  if (bytestream2_get_bytes_left(&ctx->gb) < 4)
472  return AVERROR_INVALIDDATA;
473  for (k = 0; k < 4; k++)
474  memset(dst + i + k * stride, bytestream2_get_byteu(&ctx->gb), 4);
475  break;
476  case 0xFD:
477  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
478  return AVERROR_INVALIDDATA;
479  t = bytestream2_get_byteu(&ctx->gb);
480  for (k = 0; k < 4; k++)
481  memset(dst + i + k * stride, t, 4);
482  break;
483  default:
484  if (compr == 4 && !code) {
485  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
486  return AVERROR_INVALIDDATA;
487  skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
488  i -= 4;
489  } else {
490  int mx, my;
491 
492  mx = c37_mv[(mvoff * 255 + code) * 2 ];
493  my = c37_mv[(mvoff * 255 + code) * 2 + 1];
494  codec37_mv(dst + i, prev + i + mx + my * stride,
495  ctx->height, stride, i + mx, j + my);
496  }
497  }
498  }
499  dst += stride * 4;
500  prev += stride * 4;
501  }
502  } else {
503  for (j = 0; j < height; j += 4) {
504  for (i = 0; i < width; i += 4) {
505  int code;
506  if (skip_run) {
507  skip_run--;
508  copy_block4(dst + i, prev + i, stride, stride, 4);
509  continue;
510  }
511  code = bytestream2_get_byte(&ctx->gb);
512  if (code == 0xFF) {
513  if (bytestream2_get_bytes_left(&ctx->gb) < 16)
514  return AVERROR_INVALIDDATA;
515  for (k = 0; k < 4; k++)
516  bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
517  } else if (compr == 4 && !code) {
518  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
519  return AVERROR_INVALIDDATA;
520  skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
521  i -= 4;
522  } else {
523  int mx, my;
524 
525  mx = c37_mv[(mvoff * 255 + code) * 2];
526  my = c37_mv[(mvoff * 255 + code) * 2 + 1];
527  codec37_mv(dst + i, prev + i + mx + my * stride,
528  ctx->height, stride, i + mx, j + my);
529  }
530  }
531  dst += stride * 4;
532  prev += stride * 4;
533  }
534  }
535  break;
536  default:
537  av_log(ctx->avctx, AV_LOG_ERROR,
538  "subcodec 37 compression %d not implemented\n", compr);
539  return AVERROR_PATCHWELCOME;
540  }
541 
542  return 0;
543 }
544 
545 static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1,
546  uint8_t *prev2, int stride, int tbl, int size)
547 {
548  int code, k, t;
549  uint8_t colors[2];
550  int8_t *pglyph;
551 
552  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
553  return AVERROR_INVALIDDATA;
554 
555  code = bytestream2_get_byteu(&ctx->gb);
556  if (code >= 0xF8) {
557  switch (code) {
558  case 0xFF:
559  if (size == 2) {
560  if (bytestream2_get_bytes_left(&ctx->gb) < 4)
561  return AVERROR_INVALIDDATA;
562  dst[0] = bytestream2_get_byteu(&ctx->gb);
563  dst[1] = bytestream2_get_byteu(&ctx->gb);
564  dst[0+stride] = bytestream2_get_byteu(&ctx->gb);
565  dst[1+stride] = bytestream2_get_byteu(&ctx->gb);
566  } else {
567  size >>= 1;
568  if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
569  return AVERROR_INVALIDDATA;
570  if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
571  stride, tbl, size))
572  return AVERROR_INVALIDDATA;
573  dst += size * stride;
574  prev1 += size * stride;
575  prev2 += size * stride;
576  if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
577  return AVERROR_INVALIDDATA;
578  if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
579  stride, tbl, size))
580  return AVERROR_INVALIDDATA;
581  }
582  break;
583  case 0xFE:
584  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
585  return AVERROR_INVALIDDATA;
586 
587  t = bytestream2_get_byteu(&ctx->gb);
588  for (k = 0; k < size; k++)
589  memset(dst + k * stride, t, size);
590  break;
591  case 0xFD:
592  if (bytestream2_get_bytes_left(&ctx->gb) < 3)
593  return AVERROR_INVALIDDATA;
594 
595  code = bytestream2_get_byteu(&ctx->gb);
596  pglyph = (size == 8) ? ctx->p8x8glyphs[code] : ctx->p4x4glyphs[code];
597  bytestream2_get_bufferu(&ctx->gb, colors, 2);
598 
599  for (k = 0; k < size; k++)
600  for (t = 0; t < size; t++)
601  dst[t + k * stride] = colors[!*pglyph++];
602  break;
603  case 0xFC:
604  for (k = 0; k < size; k++)
605  memcpy(dst + k * stride, prev1 + k * stride, size);
606  break;
607  default:
608  k = bytestream2_tell(&ctx->gb);
609  bytestream2_seek(&ctx->gb, tbl + (code & 7), SEEK_SET);
610  t = bytestream2_get_byte(&ctx->gb);
611  bytestream2_seek(&ctx->gb, k, SEEK_SET);
612  for (k = 0; k < size; k++)
613  memset(dst + k * stride, t, size);
614  }
615  } else {
616  int mx = motion_vectors[code][0];
617  int my = motion_vectors[code][1];
618  int index = prev2 - (const uint8_t*)ctx->frm2;
619 
620  av_assert2(index >= 0 && index < (ctx->buf_size>>1));
621 
622  if (index < - mx - my*stride ||
623  (ctx->buf_size>>1) - index < mx + size + (my + size - 1)*stride) {
624  av_log(ctx->avctx, AV_LOG_ERROR, "MV is invalid \n");
625  return AVERROR_INVALIDDATA;
626  }
627 
628  for (k = 0; k < size; k++)
629  memcpy(dst + k * stride, prev2 + mx + (my + k) * stride, size);
630  }
631 
632  return 0;
633 }
634 
635 static int old_codec47(SANMVideoContext *ctx, int top,
636  int left, int width, int height)
637 {
638  int i, j, seq, compr, new_rot, tbl_pos, skip;
639  int stride = ctx->pitch;
640  uint8_t *dst = ((uint8_t*)ctx->frm0) + left + top * stride;
641  uint8_t *prev1 = (uint8_t*)ctx->frm1;
642  uint8_t *prev2 = (uint8_t*)ctx->frm2;
643  uint32_t decoded_size;
644 
645  tbl_pos = bytestream2_tell(&ctx->gb);
646  seq = bytestream2_get_le16(&ctx->gb);
647  compr = bytestream2_get_byte(&ctx->gb);
648  new_rot = bytestream2_get_byte(&ctx->gb);
649  skip = bytestream2_get_byte(&ctx->gb);
650  bytestream2_skip(&ctx->gb, 9);
651  decoded_size = bytestream2_get_le32(&ctx->gb);
652  bytestream2_skip(&ctx->gb, 8);
653 
654  if (decoded_size > ctx->height * stride - left - top * stride) {
655  decoded_size = ctx->height * stride - left - top * stride;
656  av_log(ctx->avctx, AV_LOG_WARNING, "decoded size is too large\n");
657  }
658 
659  if (skip & 1)
660  bytestream2_skip(&ctx->gb, 0x8080);
661  if (!seq) {
662  ctx->prev_seq = -1;
663  memset(prev1, 0, ctx->height * stride);
664  memset(prev2, 0, ctx->height * stride);
665  }
666  av_dlog(ctx->avctx, "compression %d\n", compr);
667  switch (compr) {
668  case 0:
669  if (bytestream2_get_bytes_left(&ctx->gb) < width * height)
670  return AVERROR_INVALIDDATA;
671  for (j = 0; j < height; j++) {
672  bytestream2_get_bufferu(&ctx->gb, dst, width);
673  dst += stride;
674  }
675  break;
676  case 1:
677  if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1))
678  return AVERROR_INVALIDDATA;
679  for (j = 0; j < height; j += 2) {
680  for (i = 0; i < width; i += 2) {
681  dst[i] = dst[i + 1] =
682  dst[stride + i] = dst[stride + i + 1] = bytestream2_get_byteu(&ctx->gb);
683  }
684  dst += stride * 2;
685  }
686  break;
687  case 2:
688  if (seq == ctx->prev_seq + 1) {
689  for (j = 0; j < height; j += 8) {
690  for (i = 0; i < width; i += 8) {
691  if (process_block(ctx, dst + i, prev1 + i, prev2 + i, stride,
692  tbl_pos + 8, 8))
693  return AVERROR_INVALIDDATA;
694  }
695  dst += stride * 8;
696  prev1 += stride * 8;
697  prev2 += stride * 8;
698  }
699  }
700  break;
701  case 3:
702  memcpy(ctx->frm0, ctx->frm2, ctx->pitch * ctx->height);
703  break;
704  case 4:
705  memcpy(ctx->frm0, ctx->frm1, ctx->pitch * ctx->height);
706  break;
707  case 5:
708  if (rle_decode(ctx, dst, decoded_size))
709  return AVERROR_INVALIDDATA;
710  break;
711  default:
712  av_log(ctx->avctx, AV_LOG_ERROR,
713  "subcodec 47 compression %d not implemented\n", compr);
714  return AVERROR_PATCHWELCOME;
715  }
716  if (seq == ctx->prev_seq + 1)
717  ctx->rotate_code = new_rot;
718  else
719  ctx->rotate_code = 0;
720  ctx->prev_seq = seq;
721 
722  return 0;
723 }
724 
726 {
727  uint16_t codec, top, left, w, h;
728 
729  codec = bytestream2_get_le16u(&ctx->gb);
730  left = bytestream2_get_le16u(&ctx->gb);
731  top = bytestream2_get_le16u(&ctx->gb);
732  w = bytestream2_get_le16u(&ctx->gb);
733  h = bytestream2_get_le16u(&ctx->gb);
734 
735  if (!w || !h) {
736  av_log(ctx->avctx, AV_LOG_ERROR, "dimensions are invalid\n");
737  return AVERROR_INVALIDDATA;
738  }
739 
740  if (ctx->width < left + w || ctx->height < top + h) {
741  int ret = ff_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width),
742  FFMAX(top + h, ctx->height));
743  if (ret < 0)
744  return ret;
745  init_sizes(ctx, FFMAX(left + w, ctx->width),
746  FFMAX(top + h, ctx->height));
747  if (init_buffers(ctx)) {
748  av_log(ctx->avctx, AV_LOG_ERROR, "error resizing buffers\n");
749  return AVERROR(ENOMEM);
750  }
751  }
752  bytestream2_skip(&ctx->gb, 4);
753 
754  av_dlog(ctx->avctx, "subcodec %d\n", codec);
755  switch (codec) {
756  case 1:
757  case 3:
758  return old_codec1(ctx, top, left, w, h);
759  break;
760  case 37:
761  return old_codec37(ctx, top, left, w, h);
762  break;
763  case 47:
764  return old_codec47(ctx, top, left, w, h);
765  break;
766  default:
767  avpriv_request_sample(ctx->avctx, "unknown subcodec %d", codec);
768  return AVERROR_PATCHWELCOME;
769  }
770 }
771 
772 static int decode_0(SANMVideoContext *ctx)
773 {
774  uint16_t *frm = ctx->frm0;
775  int x, y;
776 
777  if (bytestream2_get_bytes_left(&ctx->gb) < ctx->width * ctx->height * 2) {
778  av_log(ctx->avctx, AV_LOG_ERROR, "insufficient data for raw frame\n");
779  return AVERROR_INVALIDDATA;
780  }
781  for (y = 0; y < ctx->height; y++) {
782  for (x = 0; x < ctx->width; x++)
783  frm[x] = bytestream2_get_le16u(&ctx->gb);
784  frm += ctx->pitch;
785  }
786  return 0;
787 }
788 
789 static int decode_nop(SANMVideoContext *ctx)
790 {
791  avpriv_request_sample(ctx->avctx, "unknown/unsupported compression type");
792  return AVERROR_PATCHWELCOME;
793 }
794 
795 static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, int pitch)
796 {
797  uint8_t *dst = (uint8_t *)pdest;
798  uint8_t *src = (uint8_t *)psrc;
799  int stride = pitch * 2;
800 
801  switch (block_size) {
802  case 2:
803  copy_block4(dst, src, stride, stride, 2);
804  break;
805  case 4:
806  copy_block8(dst, src, stride, stride, 4);
807  break;
808  case 8:
809  copy_block16(dst, src, stride, stride, 8);
810  break;
811  }
812 }
813 
814 static void fill_block(uint16_t *pdest, uint16_t color, int block_size, int pitch)
815 {
816  int x, y;
817 
818  pitch -= block_size;
819  for (y = 0; y < block_size; y++, pdest += pitch)
820  for (x = 0; x < block_size; x++)
821  *pdest++ = color;
822 }
823 
824 static int draw_glyph(SANMVideoContext *ctx, uint16_t *dst, int index, uint16_t fg_color,
825  uint16_t bg_color, int block_size, int pitch)
826 {
827  int8_t *pglyph;
828  uint16_t colors[2] = { fg_color, bg_color };
829  int x, y;
830 
831  if (index >= NGLYPHS) {
832  av_log(ctx->avctx, AV_LOG_ERROR, "ignoring nonexistent glyph #%u\n", index);
833  return AVERROR_INVALIDDATA;
834  }
835 
836  pglyph = block_size == 8 ? ctx->p8x8glyphs[index] : ctx->p4x4glyphs[index];
837  pitch -= block_size;
838 
839  for (y = 0; y < block_size; y++, dst += pitch)
840  for (x = 0; x < block_size; x++)
841  *dst++ = colors[*pglyph++];
842  return 0;
843 }
844 
845 static int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, int pitch)
846 {
847  uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
848 
849  if (block_size == 2) {
850  uint32_t indices;
851 
852  if (bytestream2_get_bytes_left(&ctx->gb) < 4)
853  return AVERROR_INVALIDDATA;
854 
855  indices = bytestream2_get_le32u(&ctx->gb);
856  dst[0] = ctx->codebook[indices & 0xFF]; indices >>= 8;
857  dst[1] = ctx->codebook[indices & 0xFF]; indices >>= 8;
858  dst[pitch] = ctx->codebook[indices & 0xFF]; indices >>= 8;
859  dst[pitch + 1] = ctx->codebook[indices & 0xFF];
860  } else {
861  uint16_t fgcolor, bgcolor;
862  int glyph;
863 
864  if (bytestream2_get_bytes_left(&ctx->gb) < 3)
865  return AVERROR_INVALIDDATA;
866 
867  glyph = bytestream2_get_byteu(&ctx->gb);
868  bgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
869  fgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
870 
871  draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
872  }
873  return 0;
874 }
875 
876 static int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, int pitch)
877 {
878  uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
879 
880  if (block_size == 2) {
881  if (bytestream2_get_bytes_left(&ctx->gb) < 8)
882  return AVERROR_INVALIDDATA;
883 
884  dst[0] = bytestream2_get_le16u(&ctx->gb);
885  dst[1] = bytestream2_get_le16u(&ctx->gb);
886  dst[pitch] = bytestream2_get_le16u(&ctx->gb);
887  dst[pitch + 1] = bytestream2_get_le16u(&ctx->gb);
888  } else {
889  uint16_t fgcolor, bgcolor;
890  int glyph;
891 
892  if (bytestream2_get_bytes_left(&ctx->gb) < 5)
893  return AVERROR_INVALIDDATA;
894 
895  glyph = bytestream2_get_byteu(&ctx->gb);
896  bgcolor = bytestream2_get_le16u(&ctx->gb);
897  fgcolor = bytestream2_get_le16u(&ctx->gb);
898 
899  draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
900  }
901  return 0;
902 }
903 
904 static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my,
905  int block_size)
906 {
907  int start_pos = cx + mx + (cy + my) * ctx->pitch;
908  int end_pos = start_pos + (block_size - 1) * (ctx->pitch + 1);
909 
910  int good = start_pos >= 0 && end_pos < (ctx->buf_size >> 1);
911 
912  if (!good) {
913  av_log(ctx->avctx, AV_LOG_ERROR, "ignoring invalid motion vector (%i, %i)->(%u, %u), block size = %u\n",
914  cx + mx, cy + my, cx, cy, block_size);
915  }
916 
917  return good;
918 }
919 
920 static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size)
921 {
922  int16_t mx, my, index;
923  int opcode;
924 
925  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
926  return AVERROR_INVALIDDATA;
927 
928  opcode = bytestream2_get_byteu(&ctx->gb);
929 
930  av_dlog(ctx->avctx, "opcode 0x%0X cx %d cy %d blk %d\n", opcode, cx, cy, blk_size);
931  switch (opcode) {
932  default:
933  mx = motion_vectors[opcode][0];
934  my = motion_vectors[opcode][1];
935 
936  if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
937  copy_block(ctx->frm0 + cx + ctx->pitch * cy,
938  ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
939  blk_size, ctx->pitch);
940  }
941  break;
942  case 0xF5:
943  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
944  return AVERROR_INVALIDDATA;
945  index = bytestream2_get_le16u(&ctx->gb);
946 
947  mx = index % ctx->width;
948  my = index / ctx->width;
949 
950  if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
951  copy_block(ctx->frm0 + cx + ctx->pitch * cy,
952  ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
953  blk_size, ctx->pitch);
954  }
955  break;
956  case 0xF6:
957  copy_block(ctx->frm0 + cx + ctx->pitch * cy,
958  ctx->frm1 + cx + ctx->pitch * cy,
959  blk_size, ctx->pitch);
960  break;
961  case 0xF7:
962  opcode_0xf7(ctx, cx, cy, blk_size, ctx->pitch);
963  break;
964 
965  case 0xF8:
966  opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
967  break;
968  case 0xF9:
969  case 0xFA:
970  case 0xFB:
971  case 0xFC:
972  fill_block(ctx->frm0 + cx + cy * ctx->pitch,
973  ctx->small_codebook[opcode - 0xf9], blk_size, ctx->pitch);
974  break;
975  case 0xFD:
976  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
977  return AVERROR_INVALIDDATA;
978  fill_block(ctx->frm0 + cx + cy * ctx->pitch,
979  ctx->codebook[bytestream2_get_byteu(&ctx->gb)], blk_size, ctx->pitch);
980  break;
981  case 0xFE:
982  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
983  return AVERROR_INVALIDDATA;
984  fill_block(ctx->frm0 + cx + cy * ctx->pitch,
985  bytestream2_get_le16u(&ctx->gb), blk_size, ctx->pitch);
986  break;
987  case 0xFF:
988  if (blk_size == 2) {
989  opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
990  } else {
991  blk_size >>= 1;
992  if (codec2subblock(ctx, cx , cy , blk_size))
993  return AVERROR_INVALIDDATA;
994  if (codec2subblock(ctx, cx + blk_size, cy , blk_size))
995  return AVERROR_INVALIDDATA;
996  if (codec2subblock(ctx, cx , cy + blk_size, blk_size))
997  return AVERROR_INVALIDDATA;
998  if (codec2subblock(ctx, cx + blk_size, cy + blk_size, blk_size))
999  return AVERROR_INVALIDDATA;
1000  }
1001  break;
1002  }
1003  return 0;
1004 }
1005 
1006 static int decode_2(SANMVideoContext *ctx)
1007 {
1008  int cx, cy, ret;
1009 
1010  for (cy = 0; cy < ctx->aligned_height; cy += 8) {
1011  for (cx = 0; cx < ctx->aligned_width; cx += 8) {
1012  if (ret = codec2subblock(ctx, cx, cy, 8))
1013  return ret;
1014  }
1015  }
1016 
1017  return 0;
1018 }
1019 
1020 static int decode_3(SANMVideoContext *ctx)
1021 {
1022  memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size);
1023  return 0;
1024 }
1025 
1026 static int decode_4(SANMVideoContext *ctx)
1027 {
1028  memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size);
1029  return 0;
1030 }
1031 
1032 static int decode_5(SANMVideoContext *ctx)
1033 {
1034 #if HAVE_BIGENDIAN
1035  uint16_t *frm;
1036  int npixels;
1037 #endif
1038  uint8_t *dst = (uint8_t*)ctx->frm0;
1039 
1040  if (rle_decode(ctx, dst, ctx->buf_size))
1041  return AVERROR_INVALIDDATA;
1042 
1043 #if HAVE_BIGENDIAN
1044  npixels = ctx->npixels;
1045  frm = ctx->frm0;
1046  while (npixels--) {
1047  *frm = av_bswap16(*frm);
1048  frm++;
1049  }
1050 #endif
1051 
1052  return 0;
1053 }
1054 
1055 static int decode_6(SANMVideoContext *ctx)
1056 {
1057  int npixels = ctx->npixels;
1058  uint16_t *frm = ctx->frm0;
1059 
1060  if (bytestream2_get_bytes_left(&ctx->gb) < npixels) {
1061  av_log(ctx->avctx, AV_LOG_ERROR, "insufficient data for frame\n");
1062  return AVERROR_INVALIDDATA;
1063  }
1064  while (npixels--)
1065  *frm++ = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1066 
1067  return 0;
1068 }
1069 
1070 static int decode_8(SANMVideoContext *ctx)
1071 {
1072  uint16_t *pdest = ctx->frm0;
1073  uint8_t *rsrc;
1074  long npixels = ctx->npixels;
1075 
1076  av_fast_malloc(&ctx->rle_buf, &ctx->rle_buf_size, npixels);
1077  if (!ctx->rle_buf) {
1078  av_log(ctx->avctx, AV_LOG_ERROR, "RLE buffer allocation failed\n");
1079  return AVERROR(ENOMEM);
1080  }
1081  rsrc = ctx->rle_buf;
1082 
1083  if (rle_decode(ctx, rsrc, npixels))
1084  return AVERROR_INVALIDDATA;
1085 
1086  while (npixels--)
1087  *pdest++ = ctx->codebook[*rsrc++];
1088 
1089  return 0;
1090 }
1091 
1092 typedef int (*frm_decoder)(SANMVideoContext *ctx);
1093 
1094 static const frm_decoder v1_decoders[] = {
1097 };
1098 
1100 {
1101  int i, ret;
1102 
1103  if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) {
1104  av_log(ctx->avctx, AV_LOG_ERROR, "too short input frame (%d bytes)\n",
1105  ret);
1106  return AVERROR_INVALIDDATA;
1107  }
1108  bytestream2_skip(&ctx->gb, 8); // skip pad
1109 
1110  hdr->width = bytestream2_get_le32u(&ctx->gb);
1111  hdr->height = bytestream2_get_le32u(&ctx->gb);
1112 
1113  if (hdr->width != ctx->width || hdr->height != ctx->height) {
1114  av_log(ctx->avctx, AV_LOG_ERROR, "variable size frames are not implemented\n");
1115  return AVERROR_PATCHWELCOME;
1116  }
1117 
1118  hdr->seq_num = bytestream2_get_le16u(&ctx->gb);
1119  hdr->codec = bytestream2_get_byteu(&ctx->gb);
1120  hdr->rotate_code = bytestream2_get_byteu(&ctx->gb);
1121 
1122  bytestream2_skip(&ctx->gb, 4); // skip pad
1123 
1124  for (i = 0; i < 4; i++)
1125  ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb);
1126  hdr->bg_color = bytestream2_get_le16u(&ctx->gb);
1127 
1128  bytestream2_skip(&ctx->gb, 2); // skip pad
1129 
1130  hdr->rle_output_size = bytestream2_get_le32u(&ctx->gb);
1131  for (i = 0; i < 256; i++)
1132  ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb);
1133 
1134  bytestream2_skip(&ctx->gb, 8); // skip pad
1135 
1136  av_dlog(ctx->avctx, "subcodec %d\n", hdr->codec);
1137  return 0;
1138 }
1139 
1140 static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color)
1141 {
1142  while (buf_size--)
1143  *pbuf++ = color;
1144 }
1145 
1147 {
1148  uint8_t *dst;
1149  const uint8_t *src = (uint8_t*) ctx->frm0;
1150  int ret, dstpitch, height = ctx->height;
1151  int srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1);
1152 
1153  if ((ret = ff_get_buffer(ctx->avctx, ctx->frame, 0)) < 0)
1154  return ret;
1155 
1156  dst = ctx->frame->data[0];
1157  dstpitch = ctx->frame->linesize[0];
1158 
1159  while (height--) {
1160  memcpy(dst, src, srcpitch);
1161  src += srcpitch;
1162  dst += dstpitch;
1163  }
1164 
1165  return 0;
1166 }
1167 
1168 static int decode_frame(AVCodecContext *avctx, void *data,
1169  int *got_frame_ptr, AVPacket *pkt)
1170 {
1171  SANMVideoContext *ctx = avctx->priv_data;
1172  int i, ret;
1173 
1174  ctx->frame = data;
1175  bytestream2_init(&ctx->gb, pkt->data, pkt->size);
1176 
1177  if (!ctx->version) {
1178  int to_store = 0;
1179 
1180  while (bytestream2_get_bytes_left(&ctx->gb) >= 8) {
1181  uint32_t sig, size;
1182  int pos;
1183 
1184  sig = bytestream2_get_be32u(&ctx->gb);
1185  size = bytestream2_get_be32u(&ctx->gb);
1186  pos = bytestream2_tell(&ctx->gb);
1187 
1188  if (bytestream2_get_bytes_left(&ctx->gb) < size) {
1189  av_log(avctx, AV_LOG_ERROR, "incorrect chunk size %d\n", size);
1190  break;
1191  }
1192  switch (sig) {
1193  case MKBETAG('N', 'P', 'A', 'L'):
1194  if (size != 256 * 3) {
1195  av_log(avctx, AV_LOG_ERROR, "incorrect palette block size %d\n",
1196  size);
1197  return AVERROR_INVALIDDATA;
1198  }
1199  for (i = 0; i < 256; i++)
1200  ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
1201  break;
1202  case MKBETAG('F', 'O', 'B', 'J'):
1203  if (size < 16)
1204  return AVERROR_INVALIDDATA;
1205  if (ret = process_frame_obj(ctx))
1206  return ret;
1207  break;
1208  case MKBETAG('X', 'P', 'A', 'L'):
1209  if (size == 6 || size == 4) {
1210  uint8_t tmp[3];
1211  int j;
1212 
1213  for (i = 0; i < 256; i++) {
1214  for (j = 0; j < 3; j++) {
1215  int t = (ctx->pal[i] >> (16 - j * 8)) & 0xFF;
1216  tmp[j] = av_clip_uint8((t * 129 + ctx->delta_pal[i * 3 + j]) >> 7);
1217  }
1218  ctx->pal[i] = 0xFFU << 24 | AV_RB24(tmp);
1219  }
1220  } else {
1221  if (size < 768 * 2 + 4) {
1222  av_log(avctx, AV_LOG_ERROR, "incorrect palette change block size %d\n",
1223  size);
1224  return AVERROR_INVALIDDATA;
1225  }
1226  bytestream2_skipu(&ctx->gb, 4);
1227  for (i = 0; i < 768; i++)
1228  ctx->delta_pal[i] = bytestream2_get_le16u(&ctx->gb);
1229  if (size >= 768 * 5 + 4) {
1230  for (i = 0; i < 256; i++)
1231  ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
1232  } else {
1233  memset(ctx->pal, 0, sizeof(ctx->pal));
1234  }
1235  }
1236  break;
1237  case MKBETAG('S', 'T', 'O', 'R'):
1238  to_store = 1;
1239  break;
1240  case MKBETAG('F', 'T', 'C', 'H'):
1241  memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size);
1242  break;
1243  default:
1244  bytestream2_skip(&ctx->gb, size);
1245  av_log(avctx, AV_LOG_DEBUG, "unknown/unsupported chunk %x\n", sig);
1246  break;
1247  }
1248 
1249  bytestream2_seek(&ctx->gb, pos + size, SEEK_SET);
1250  if (size & 1)
1251  bytestream2_skip(&ctx->gb, 1);
1252  }
1253  if (to_store)
1254  memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size);
1255  if ((ret = copy_output(ctx, NULL)))
1256  return ret;
1257  memcpy(ctx->frame->data[1], ctx->pal, 1024);
1258  } else {
1260 
1261  if ((ret = read_frame_header(ctx, &header)))
1262  return ret;
1263 
1264  ctx->rotate_code = header.rotate_code;
1265  if ((ctx->frame->key_frame = !header.seq_num)) {
1267  fill_frame(ctx->frm1, ctx->npixels, header.bg_color);
1268  fill_frame(ctx->frm2, ctx->npixels, header.bg_color);
1269  } else {
1271  }
1272 
1273  if (header.codec < FF_ARRAY_ELEMS(v1_decoders)) {
1274  if ((ret = v1_decoders[header.codec](ctx))) {
1275  av_log(avctx, AV_LOG_ERROR,
1276  "subcodec %d: error decoding frame\n", header.codec);
1277  return ret;
1278  }
1279  } else {
1280  avpriv_request_sample(avctx, "subcodec %d",
1281  header.codec);
1282  return AVERROR_PATCHWELCOME;
1283  }
1284 
1285  if ((ret = copy_output(ctx, &header)))
1286  return ret;
1287  }
1288  if (ctx->rotate_code)
1289  rotate_bufs(ctx, ctx->rotate_code);
1290 
1291  *got_frame_ptr = 1;
1292 
1293  return pkt->size;
1294 }
1295 
1297  .name = "sanm",
1298  .long_name = NULL_IF_CONFIG_SMALL("LucasArts SMUSH video"),
1299  .type = AVMEDIA_TYPE_VIDEO,
1300  .id = AV_CODEC_ID_SANM,
1301  .priv_data_size = sizeof(SANMVideoContext),
1302  .init = decode_init,
1303  .close = decode_end,
1304  .decode = decode_frame,
1305  .capabilities = CODEC_CAP_DR1,
1306 };