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  if (av_image_check_size(FFMAX(left + w, ctx->width),
742  FFMAX(top + h, ctx->height), 0, ctx->avctx) < 0)
743  return AVERROR_INVALIDDATA;
744  avcodec_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width),
745  FFMAX(top + h, ctx->height));
746  init_sizes(ctx, FFMAX(left + w, ctx->width),
747  FFMAX(top + h, ctx->height));
748  if (init_buffers(ctx)) {
749  av_log(ctx->avctx, AV_LOG_ERROR, "error resizing buffers\n");
750  return AVERROR(ENOMEM);
751  }
752  }
753  bytestream2_skip(&ctx->gb, 4);
754 
755  av_dlog(ctx->avctx, "subcodec %d\n", codec);
756  switch (codec) {
757  case 1:
758  case 3:
759  return old_codec1(ctx, top, left, w, h);
760  break;
761  case 37:
762  return old_codec37(ctx, top, left, w, h);
763  break;
764  case 47:
765  return old_codec47(ctx, top, left, w, h);
766  break;
767  default:
768  avpriv_request_sample(ctx->avctx, "unknown subcodec %d", codec);
769  return AVERROR_PATCHWELCOME;
770  }
771 }
772 
773 static int decode_0(SANMVideoContext *ctx)
774 {
775  uint16_t *frm = ctx->frm0;
776  int x, y;
777 
778  if (bytestream2_get_bytes_left(&ctx->gb) < ctx->width * ctx->height * 2) {
779  av_log(ctx->avctx, AV_LOG_ERROR, "insufficient data for raw frame\n");
780  return AVERROR_INVALIDDATA;
781  }
782  for (y = 0; y < ctx->height; y++) {
783  for (x = 0; x < ctx->width; x++)
784  frm[x] = bytestream2_get_le16u(&ctx->gb);
785  frm += ctx->pitch;
786  }
787  return 0;
788 }
789 
790 static int decode_nop(SANMVideoContext *ctx)
791 {
792  avpriv_request_sample(ctx->avctx, "unknown/unsupported compression type");
793  return AVERROR_PATCHWELCOME;
794 }
795 
796 static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, int pitch)
797 {
798  uint8_t *dst = (uint8_t *)pdest;
799  uint8_t *src = (uint8_t *)psrc;
800  int stride = pitch * 2;
801 
802  switch (block_size) {
803  case 2:
804  copy_block4(dst, src, stride, stride, 2);
805  break;
806  case 4:
807  copy_block8(dst, src, stride, stride, 4);
808  break;
809  case 8:
810  copy_block16(dst, src, stride, stride, 8);
811  break;
812  }
813 }
814 
815 static void fill_block(uint16_t *pdest, uint16_t color, int block_size, int pitch)
816 {
817  int x, y;
818 
819  pitch -= block_size;
820  for (y = 0; y < block_size; y++, pdest += pitch)
821  for (x = 0; x < block_size; x++)
822  *pdest++ = color;
823 }
824 
825 static int draw_glyph(SANMVideoContext *ctx, uint16_t *dst, int index, uint16_t fg_color,
826  uint16_t bg_color, int block_size, int pitch)
827 {
828  int8_t *pglyph;
829  uint16_t colors[2] = { fg_color, bg_color };
830  int x, y;
831 
832  if (index >= NGLYPHS) {
833  av_log(ctx->avctx, AV_LOG_ERROR, "ignoring nonexistent glyph #%u\n", index);
834  return AVERROR_INVALIDDATA;
835  }
836 
837  pglyph = block_size == 8 ? ctx->p8x8glyphs[index] : ctx->p4x4glyphs[index];
838  pitch -= block_size;
839 
840  for (y = 0; y < block_size; y++, dst += pitch)
841  for (x = 0; x < block_size; x++)
842  *dst++ = colors[*pglyph++];
843  return 0;
844 }
845 
846 static int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, int pitch)
847 {
848  uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
849 
850  if (block_size == 2) {
851  uint32_t indices;
852 
853  if (bytestream2_get_bytes_left(&ctx->gb) < 4)
854  return AVERROR_INVALIDDATA;
855 
856  indices = bytestream2_get_le32u(&ctx->gb);
857  dst[0] = ctx->codebook[indices & 0xFF]; indices >>= 8;
858  dst[1] = ctx->codebook[indices & 0xFF]; indices >>= 8;
859  dst[pitch] = ctx->codebook[indices & 0xFF]; indices >>= 8;
860  dst[pitch + 1] = ctx->codebook[indices & 0xFF];
861  } else {
862  uint16_t fgcolor, bgcolor;
863  int glyph;
864 
865  if (bytestream2_get_bytes_left(&ctx->gb) < 3)
866  return AVERROR_INVALIDDATA;
867 
868  glyph = bytestream2_get_byteu(&ctx->gb);
869  bgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
870  fgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
871 
872  draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
873  }
874  return 0;
875 }
876 
877 static int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, int pitch)
878 {
879  uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
880 
881  if (block_size == 2) {
882  if (bytestream2_get_bytes_left(&ctx->gb) < 8)
883  return AVERROR_INVALIDDATA;
884 
885  dst[0] = bytestream2_get_le16u(&ctx->gb);
886  dst[1] = bytestream2_get_le16u(&ctx->gb);
887  dst[pitch] = bytestream2_get_le16u(&ctx->gb);
888  dst[pitch + 1] = bytestream2_get_le16u(&ctx->gb);
889  } else {
890  uint16_t fgcolor, bgcolor;
891  int glyph;
892 
893  if (bytestream2_get_bytes_left(&ctx->gb) < 5)
894  return AVERROR_INVALIDDATA;
895 
896  glyph = bytestream2_get_byteu(&ctx->gb);
897  bgcolor = bytestream2_get_le16u(&ctx->gb);
898  fgcolor = bytestream2_get_le16u(&ctx->gb);
899 
900  draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
901  }
902  return 0;
903 }
904 
905 static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my,
906  int block_size)
907 {
908  int start_pos = cx + mx + (cy + my) * ctx->pitch;
909  int end_pos = start_pos + (block_size - 1) * (ctx->pitch + 1);
910 
911  int good = start_pos >= 0 && end_pos < (ctx->buf_size >> 1);
912 
913  if (!good) {
914  av_log(ctx->avctx, AV_LOG_ERROR, "ignoring invalid motion vector (%i, %i)->(%u, %u), block size = %u\n",
915  cx + mx, cy + my, cx, cy, block_size);
916  }
917 
918  return good;
919 }
920 
921 static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size)
922 {
923  int16_t mx, my, index;
924  int opcode;
925 
926  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
927  return AVERROR_INVALIDDATA;
928 
929  opcode = bytestream2_get_byteu(&ctx->gb);
930 
931  av_dlog(ctx->avctx, "opcode 0x%0X cx %d cy %d blk %d\n", opcode, cx, cy, blk_size);
932  switch (opcode) {
933  default:
934  mx = motion_vectors[opcode][0];
935  my = motion_vectors[opcode][1];
936 
937  if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
938  copy_block(ctx->frm0 + cx + ctx->pitch * cy,
939  ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
940  blk_size, ctx->pitch);
941  }
942  break;
943  case 0xF5:
944  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
945  return AVERROR_INVALIDDATA;
946  index = bytestream2_get_le16u(&ctx->gb);
947 
948  mx = index % ctx->width;
949  my = index / ctx->width;
950 
951  if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
952  copy_block(ctx->frm0 + cx + ctx->pitch * cy,
953  ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
954  blk_size, ctx->pitch);
955  }
956  break;
957  case 0xF6:
958  copy_block(ctx->frm0 + cx + ctx->pitch * cy,
959  ctx->frm1 + cx + ctx->pitch * cy,
960  blk_size, ctx->pitch);
961  break;
962  case 0xF7:
963  opcode_0xf7(ctx, cx, cy, blk_size, ctx->pitch);
964  break;
965 
966  case 0xF8:
967  opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
968  break;
969  case 0xF9:
970  case 0xFA:
971  case 0xFB:
972  case 0xFC:
973  fill_block(ctx->frm0 + cx + cy * ctx->pitch,
974  ctx->small_codebook[opcode - 0xf9], blk_size, ctx->pitch);
975  break;
976  case 0xFD:
977  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
978  return AVERROR_INVALIDDATA;
979  fill_block(ctx->frm0 + cx + cy * ctx->pitch,
980  ctx->codebook[bytestream2_get_byteu(&ctx->gb)], blk_size, ctx->pitch);
981  break;
982  case 0xFE:
983  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
984  return AVERROR_INVALIDDATA;
985  fill_block(ctx->frm0 + cx + cy * ctx->pitch,
986  bytestream2_get_le16u(&ctx->gb), blk_size, ctx->pitch);
987  break;
988  case 0xFF:
989  if (blk_size == 2) {
990  opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
991  } else {
992  blk_size >>= 1;
993  if (codec2subblock(ctx, cx , cy , blk_size))
994  return AVERROR_INVALIDDATA;
995  if (codec2subblock(ctx, cx + blk_size, cy , blk_size))
996  return AVERROR_INVALIDDATA;
997  if (codec2subblock(ctx, cx , cy + blk_size, blk_size))
998  return AVERROR_INVALIDDATA;
999  if (codec2subblock(ctx, cx + blk_size, cy + blk_size, blk_size))
1000  return AVERROR_INVALIDDATA;
1001  }
1002  break;
1003  }
1004  return 0;
1005 }
1006 
1007 static int decode_2(SANMVideoContext *ctx)
1008 {
1009  int cx, cy, ret;
1010 
1011  for (cy = 0; cy < ctx->aligned_height; cy += 8) {
1012  for (cx = 0; cx < ctx->aligned_width; cx += 8) {
1013  if (ret = codec2subblock(ctx, cx, cy, 8))
1014  return ret;
1015  }
1016  }
1017 
1018  return 0;
1019 }
1020 
1021 static int decode_3(SANMVideoContext *ctx)
1022 {
1023  memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size);
1024  return 0;
1025 }
1026 
1027 static int decode_4(SANMVideoContext *ctx)
1028 {
1029  memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size);
1030  return 0;
1031 }
1032 
1033 static int decode_5(SANMVideoContext *ctx)
1034 {
1035 #if HAVE_BIGENDIAN
1036  uint16_t *frm;
1037  int npixels;
1038 #endif
1039  uint8_t *dst = (uint8_t*)ctx->frm0;
1040 
1041  if (rle_decode(ctx, dst, ctx->buf_size))
1042  return AVERROR_INVALIDDATA;
1043 
1044 #if HAVE_BIGENDIAN
1045  npixels = ctx->npixels;
1046  frm = ctx->frm0;
1047  while (npixels--)
1048  *frm++ = av_bswap16(*frm);
1049 #endif
1050 
1051  return 0;
1052 }
1053 
1054 static int decode_6(SANMVideoContext *ctx)
1055 {
1056  int npixels = ctx->npixels;
1057  uint16_t *frm = ctx->frm0;
1058 
1059  if (bytestream2_get_bytes_left(&ctx->gb) < npixels) {
1060  av_log(ctx->avctx, AV_LOG_ERROR, "insufficient data for frame\n");
1061  return AVERROR_INVALIDDATA;
1062  }
1063  while (npixels--)
1064  *frm++ = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1065 
1066  return 0;
1067 }
1068 
1069 static int decode_8(SANMVideoContext *ctx)
1070 {
1071  uint16_t *pdest = ctx->frm0;
1072  uint8_t *rsrc;
1073  long npixels = ctx->npixels;
1074 
1075  av_fast_malloc(&ctx->rle_buf, &ctx->rle_buf_size, npixels);
1076  if (!ctx->rle_buf) {
1077  av_log(ctx->avctx, AV_LOG_ERROR, "RLE buffer allocation failed\n");
1078  return AVERROR(ENOMEM);
1079  }
1080  rsrc = ctx->rle_buf;
1081 
1082  if (rle_decode(ctx, rsrc, npixels))
1083  return AVERROR_INVALIDDATA;
1084 
1085  while (npixels--)
1086  *pdest++ = ctx->codebook[*rsrc++];
1087 
1088  return 0;
1089 }
1090 
1091 typedef int (*frm_decoder)(SANMVideoContext *ctx);
1092 
1093 static const frm_decoder v1_decoders[] = {
1096 };
1097 
1099 {
1100  int i, ret;
1101 
1102  if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) {
1103  av_log(ctx->avctx, AV_LOG_ERROR, "too short input frame (%d bytes)\n",
1104  ret);
1105  return AVERROR_INVALIDDATA;
1106  }
1107  bytestream2_skip(&ctx->gb, 8); // skip pad
1108 
1109  hdr->width = bytestream2_get_le32u(&ctx->gb);
1110  hdr->height = bytestream2_get_le32u(&ctx->gb);
1111 
1112  if (hdr->width != ctx->width || hdr->height != ctx->height) {
1113  av_log(ctx->avctx, AV_LOG_ERROR, "variable size frames are not implemented\n");
1114  return AVERROR_PATCHWELCOME;
1115  }
1116 
1117  hdr->seq_num = bytestream2_get_le16u(&ctx->gb);
1118  hdr->codec = bytestream2_get_byteu(&ctx->gb);
1119  hdr->rotate_code = bytestream2_get_byteu(&ctx->gb);
1120 
1121  bytestream2_skip(&ctx->gb, 4); // skip pad
1122 
1123  for (i = 0; i < 4; i++)
1124  ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb);
1125  hdr->bg_color = bytestream2_get_le16u(&ctx->gb);
1126 
1127  bytestream2_skip(&ctx->gb, 2); // skip pad
1128 
1129  hdr->rle_output_size = bytestream2_get_le32u(&ctx->gb);
1130  for (i = 0; i < 256; i++)
1131  ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb);
1132 
1133  bytestream2_skip(&ctx->gb, 8); // skip pad
1134 
1135  av_dlog(ctx->avctx, "subcodec %d\n", hdr->codec);
1136  return 0;
1137 }
1138 
1139 static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color)
1140 {
1141  while (buf_size--)
1142  *pbuf++ = color;
1143 }
1144 
1146 {
1147  uint8_t *dst;
1148  const uint8_t *src = (uint8_t*) ctx->frm0;
1149  int ret, dstpitch, height = ctx->height;
1150  int srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1);
1151 
1152  if ((ret = ff_get_buffer(ctx->avctx, ctx->frame, 0)) < 0)
1153  return ret;
1154 
1155  dst = ctx->frame->data[0];
1156  dstpitch = ctx->frame->linesize[0];
1157 
1158  while (height--) {
1159  memcpy(dst, src, srcpitch);
1160  src += srcpitch;
1161  dst += dstpitch;
1162  }
1163 
1164  return 0;
1165 }
1166 
1167 static int decode_frame(AVCodecContext *avctx, void *data,
1168  int *got_frame_ptr, AVPacket *pkt)
1169 {
1170  SANMVideoContext *ctx = avctx->priv_data;
1171  int i, ret;
1172 
1173  ctx->frame = data;
1174  bytestream2_init(&ctx->gb, pkt->data, pkt->size);
1175 
1176  if (!ctx->version) {
1177  int to_store = 0;
1178 
1179  while (bytestream2_get_bytes_left(&ctx->gb) >= 8) {
1180  uint32_t sig, size;
1181  int pos;
1182 
1183  sig = bytestream2_get_be32u(&ctx->gb);
1184  size = bytestream2_get_be32u(&ctx->gb);
1185  pos = bytestream2_tell(&ctx->gb);
1186 
1187  if (bytestream2_get_bytes_left(&ctx->gb) < size) {
1188  av_log(avctx, AV_LOG_ERROR, "incorrect chunk size %d\n", size);
1189  break;
1190  }
1191  switch (sig) {
1192  case MKBETAG('N', 'P', 'A', 'L'):
1193  if (size != 256 * 3) {
1194  av_log(avctx, AV_LOG_ERROR, "incorrect palette block size %d\n",
1195  size);
1196  return AVERROR_INVALIDDATA;
1197  }
1198  for (i = 0; i < 256; i++)
1199  ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
1200  break;
1201  case MKBETAG('F', 'O', 'B', 'J'):
1202  if (size < 16)
1203  return AVERROR_INVALIDDATA;
1204  if (ret = process_frame_obj(ctx))
1205  return ret;
1206  break;
1207  case MKBETAG('X', 'P', 'A', 'L'):
1208  if (size == 6 || size == 4) {
1209  uint8_t tmp[3];
1210  int j;
1211 
1212  for (i = 0; i < 256; i++) {
1213  for (j = 0; j < 3; j++) {
1214  int t = (ctx->pal[i] >> (16 - j * 8)) & 0xFF;
1215  tmp[j] = av_clip_uint8((t * 129 + ctx->delta_pal[i * 3 + j]) >> 7);
1216  }
1217  ctx->pal[i] = 0xFFU << 24 | AV_RB24(tmp);
1218  }
1219  } else {
1220  if (size < 768 * 2 + 4) {
1221  av_log(avctx, AV_LOG_ERROR, "incorrect palette change block size %d\n",
1222  size);
1223  return AVERROR_INVALIDDATA;
1224  }
1225  bytestream2_skipu(&ctx->gb, 4);
1226  for (i = 0; i < 768; i++)
1227  ctx->delta_pal[i] = bytestream2_get_le16u(&ctx->gb);
1228  if (size >= 768 * 5 + 4) {
1229  for (i = 0; i < 256; i++)
1230  ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
1231  } else {
1232  memset(ctx->pal, 0, sizeof(ctx->pal));
1233  }
1234  }
1235  break;
1236  case MKBETAG('S', 'T', 'O', 'R'):
1237  to_store = 1;
1238  break;
1239  case MKBETAG('F', 'T', 'C', 'H'):
1240  memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size);
1241  break;
1242  default:
1243  bytestream2_skip(&ctx->gb, size);
1244  av_log(avctx, AV_LOG_DEBUG, "unknown/unsupported chunk %x\n", sig);
1245  break;
1246  }
1247 
1248  bytestream2_seek(&ctx->gb, pos + size, SEEK_SET);
1249  if (size & 1)
1250  bytestream2_skip(&ctx->gb, 1);
1251  }
1252  if (to_store)
1253  memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size);
1254  if ((ret = copy_output(ctx, NULL)))
1255  return ret;
1256  memcpy(ctx->frame->data[1], ctx->pal, 1024);
1257  } else {
1258  SANMFrameHeader header;
1259 
1260  if ((ret = read_frame_header(ctx, &header)))
1261  return ret;
1262 
1263  ctx->rotate_code = header.rotate_code;
1264  if ((ctx->frame->key_frame = !header.seq_num)) {
1266  fill_frame(ctx->frm1, ctx->npixels, header.bg_color);
1267  fill_frame(ctx->frm2, ctx->npixels, header.bg_color);
1268  } else {
1270  }
1271 
1272  if (header.codec < FF_ARRAY_ELEMS(v1_decoders)) {
1273  if ((ret = v1_decoders[header.codec](ctx))) {
1274  av_log(avctx, AV_LOG_ERROR,
1275  "subcodec %d: error decoding frame\n", header.codec);
1276  return ret;
1277  }
1278  } else {
1279  avpriv_request_sample(avctx, "subcodec %d",
1280  header.codec);
1281  return AVERROR_PATCHWELCOME;
1282  }
1283 
1284  if ((ret = copy_output(ctx, &header)))
1285  return ret;
1286  }
1287  if (ctx->rotate_code)
1288  rotate_bufs(ctx, ctx->rotate_code);
1289 
1290  *got_frame_ptr = 1;
1291 
1292  return pkt->size;
1293 }
1294 
1296  .name = "sanm",
1297  .type = AVMEDIA_TYPE_VIDEO,
1298  .id = AV_CODEC_ID_SANM,
1299  .priv_data_size = sizeof(SANMVideoContext),
1300  .init = decode_init,
1301  .close = decode_end,
1302  .decode = decode_frame,
1303  .capabilities = CODEC_CAP_DR1,
1304  .long_name = NULL_IF_CONFIG_SMALL("LucasArts SMUSH video"),
1305 };