1
2 #include "config.h"
3 #include "mvi.h"
4
5 #ifndef NO_LZO
6 # include "minilzo/minilzo.h"
7 # define IF_LZO(x) x
8 #else
9 # define IF_LZO(x) ((void)0)
10 #endif
11
12 /* ======================================================================== */
13 /* Movie format is little endian on all targets. All multibyte fields */
14 /* get sent LSbyte first. All bitmaps are ls-bit first. Packed pixels */
15 /* fill LSnibble before MSnibble. */
16 /* */
17 /* FILE HEADER: */
18 /* 4 bytes Signature: 0x4A 0x5A 0x6A 0x7A */
19 /* 2 bytes X resolution (always 0xA0 0x00 (160) for now) */
20 /* 2 bytes Y resolution (always 0xC8 0x00 (200) for now) */
21 /* */
22 /* Note that the file header can optionally appear after any frame. */
23 /* This makes it easy to concatenate two movies together. The decoder */
24 /* should look for a file header when decoding any frame. It's up to */
25 /* the decoder how it handles two movies w/ different resolutions. */
26 /* */
27 /* FRAME FORMAT: */
28 /* 4 bytes Total frame length (incl. header) */
29 /* 3 bytes Frame number */
30 /* 1 byte Flags */
31 /* Bit 0: Frame sent (0 == skip, 1 == present) */
32 /* Absent frames assumed to be repeat of prev */
33 /* Bit 1: Bounding boxes sent (0 == skip, 1 == present) */
34 /* Absent bounding boxes assumed to be repeat. */
35 /* Bit 2: RLE compressed */
36 /* Bit 3: In-frame row-repeat map (1 == present) */
37 /* Bit 4: Frame-to-frame row delta map (1 == present) */
38 /* Bit 5: LZO compressed (0 == no, 1 == yes) */
39 /* Bit 6..7: Reserved */
40 /* */
41 /* (Note: Remainder of frame is LZO compressed if LZO = 1) */
42 /* */
43 /* 32 bytes MOB bounding boxes in 8 4-byte records (if sent.) */
44 /* 1 byte each for x0, y0, x1, y1 */
45 /* N bytes Row Delta Map (if sent.) */
46 /* N bytes Row Repeat Map (if sent.) */
47 /* N bytes Image data (if sent.) */
48 /* */
49 /* ROW DELTA MAP */
50 /* */
51 /* If present, the row-delta map indicates which rows are exact repeats */
52 /* of the previous frame. This eliminates rows from the raster scan */
53 /* that get sent. Row-delta compression happens before row-repeat, RLE or */
54 /* copy-through. The row-delta map is 1-bit-per-row bitmap that */
55 /* indicates which rows are copies of the ones from the previous frame. */
56 /* Rows are packed in LSB first, in a byte-oriented bitmap. The */
57 /* bitmap length is always rounded to a whole number of bytes. */
58 /* */
59 /* The length of the row-delta map is implied by the Y dimension of */
60 /* the screen. */
61 /* */
62 /* ROW REPEAT MAP */
63 /* */
64 /* If present, the row-repeat map indicates which rows are repeats */
65 /* of the rows above them. This eliminates rows from the raster scan */
66 /* that get sent. Row-repeat compression happens before RLE or */
67 /* copy-through. The row-repeat map is 1-bit-per-row bitmap that */
68 /* indicates which rows are copies of the ones above it. Copies are */
69 /* recursive, so the same row can get copied down multiple times. */
70 /* Rows are packed in LSB first, in a byte-oriented bitmap. The */
71 /* bitmap length is always rounded to a whole number of bytes. */
72 /* */
73 /* The length of the row-repeat map is implied by the Y dimension of */
74 /* the screen, minus the rows compressed away by the row-delta map. */
75 /* */
76 /* IMAGE DATA FORMAT: */
77 /* N bytes Pixel data */
78 /* */
79 /* RLE COMPRESSED IMAGE */
80 /* */
81 /* For RLE-compressed images, image is composed of "copy runs" and */
82 /* "fill runs". All image pixels are contained in a run and so an */
83 /* image consists of "run records." Runs are always even length. */
84 /* The RLE compressor scans from upper left to lower right in normal */
85 /* raster order, and concatenates rows. */
86 /* */
87 /* COPY RUN: 2 pixels to 256 pixels, always even length. */
88 /* */
89 /* Header byte: */
90 /* Bit 0: 0 (indicates "copy run") */
91 /* Bit 7..1: Bits 7..1 of "run_length - 2". */
92 /* */
93 /* Data byte(s): */
94 /* Bit 7..4: Second pixel */
95 /* Bit 3..0: First pixel */
96 /* */
97 /* FILL RUN: 2 pixels to 526 pixels. */
98 /* */
99 /* Header byte: */
100 /* Bit 0: 1 (indicates "fill run") */
101 /* Bit 3..1: Run length (2..14), or 000 to indicate overflow. */
102 /* Bit 7..4: Fill color. */
103 /* */
104 /* If encoded run length = 000, a second header byte provides */
105 /* an 8-bit run length in the range 0..510, to which 16 gets */
106 /* added for the actual run length. Thus, the value stored */
107 /* in the byte is (run_length - 16) / 2. */
108 /* */
109 /* UNCOMPRESSED IMAGE */
110 /* */
111 /* For uncompressed images, there's simply a x_dim * y_dim / 2 byte */
112 /* record of packed pixels. Pixels are packed into bytes with the */
113 /* first pixel in bits 3..0, and the second pixel in bits 7..4. */
114 /* ======================================================================== */
115
116
117 #define FLG_FRSENT ( 1)
118 #define FLG_BBSENT ( 2)
119 #define FLG_RLECMP ( 4)
120 #define FLG_RPTMAP ( 8)
121 #define FLG_DLTMAP (16)
122 #define FLG_LZOCMP (32)
123
124 LOCAL uint8_t *enc_vid = NULL, *enc_buf = NULL, *enc_vid2;
125 #ifndef NO_LZO
126 LOCAL uint8_t *lzo_wrk = NULL, *lzo_tmp = NULL;
127 #endif
128 LOCAL uint32_t rowrpt[MVI_MAX_Y >> 5];
129 LOCAL uint32_t rowdlt[MVI_MAX_Y >> 5];
130
131 #define ENC_BUF_SZ (MVI_MAX_X * MVI_MAX_Y + 128)
132
133
134 /* ======================================================================== */
135 /* MVI_INIT: Initialize movie tracking structure and scratch areas */
136 /* ======================================================================== */
mvi_init(mvi_t * movie,int x_dim,int y_dim)137 void mvi_init(mvi_t *movie, int x_dim, int y_dim)
138 {
139 int i, j;
140
141 if (x_dim > MVI_MAX_X || y_dim > MVI_MAX_Y)
142 {
143 fprintf(stderr, "MVI_INIT: %dx%d movie dimensions too large\n",
144 x_dim, y_dim);
145 exit(1);
146 }
147
148 movie->x_dim = x_dim;
149 movie->y_dim = y_dim;
150
151 for (i = 0; i < 8; i++)
152 for (j = 0; j < 4; j++)
153 movie->bbox[i][j] = 0;
154
155 movie->vid = CALLOC(uint8_t, x_dim*y_dim); /* 1 byte/pixel, just like gfx */
156 movie->fr = 0;
157 movie->f = NULL;
158
159 if (!enc_buf ) enc_buf = CALLOC(uint8_t, ENC_BUF_SZ);
160 if (!enc_vid ) enc_vid = CALLOC(uint8_t, MVI_MAX_X * MVI_MAX_Y);
161 if (!enc_vid2) enc_vid2 = CALLOC(uint8_t, MVI_MAX_X * MVI_MAX_Y);
162
163 #ifndef NO_LZO
164 if (!lzo_wrk) lzo_wrk = CALLOC(uint8_t, LZO1X_MEM_COMPRESS);
165 if (!lzo_tmp) lzo_tmp = CALLOC(uint8_t, ENC_BUF_SZ);
166 #endif
167
168 if (!enc_buf || !enc_vid || !enc_vid2 || !movie->vid)
169 {
170 perror("MVI_INIT");
171 exit(1);
172 }
173 }
174
175 /* ======================================================================== */
176 /* MVI_WR_FRAME: Encode and write a movie frame to the movie file. */
177 /* ======================================================================== */
mvi_wr_frame(mvi_t * movie,uint8_t * vid,uint8_t bbox[8][4])178 void mvi_wr_frame(mvi_t *movie, uint8_t *vid, uint8_t bbox[8][4])
179 {
180 int send_bbox = 0, send_frame = 0, send_rle = 0;
181 int send_rowrpt = 0, lzo_comp = 0;
182 int enc_height_rd = movie->y_dim, enc_height = movie->y_dim;
183 int send_rowdlt = 0, rowdlt_ok = 0;
184 int yi, yo;
185 uint8_t header_byte = 0;
186 int rle_max_len;
187 uint8_t *enc_hdr;
188 uint8_t *enc_ptr = enc_buf;
189 uint8_t *evid = vid;
190 int i, j;
191
192 /* -------------------------------------------------------------------- */
193 /* If this is frame #0, send a file header. */
194 /* -------------------------------------------------------------------- */
195 if (movie->fr == 0)
196 {
197 /* signature */
198 *enc_ptr++ = 0x4A;
199 *enc_ptr++ = 0x5A;
200 *enc_ptr++ = 0x6A;
201 *enc_ptr++ = 0x7A;
202 /* dimensions */
203 *enc_ptr++ = (movie->x_dim >> 0) & 0xFF;
204 *enc_ptr++ = (movie->x_dim >> 8) & 0xFF;
205 *enc_ptr++ = (movie->y_dim >> 0) & 0xFF;
206 *enc_ptr++ = (movie->y_dim >> 8) & 0xFF;
207
208 movie->rpt_frames = 0;
209 movie->rpt_rows = 0;
210 movie->tot_bytes = 0;
211 #ifndef NO_LZO
212 movie->tot_lzosave= 0;
213 #endif
214 memset(movie->vid, 0xFF, movie->x_dim * movie->y_dim); /* force 1st */
215 }
216
217 enc_hdr = enc_ptr;
218 enc_ptr += 8;
219
220 /* -------------------------------------------------------------------- */
221 /* Decide whether to send bounding box and frame. */
222 /* -------------------------------------------------------------------- */
223 send_frame = memcmp(movie->vid, vid, movie->x_dim * movie->y_dim);
224 send_bbox = memcmp((void*)movie->bbox, bbox, sizeof(movie->bbox));
225
226 if (!send_frame) movie->rpt_frames++;
227
228 if (send_frame && /* only on frames we send */
229 movie->fr > 0 && /* never the first frame */
230 ((movie->fr - movie->rpt_frames) & 15) != 0) /* force no 1 ever 16 */
231 rowdlt_ok = 1;
232
233
234 /* -------------------------------------------------------------------- */
235 /* If we're sending the bounding boxes, plug them in now. */
236 /* -------------------------------------------------------------------- */
237 if (send_bbox)
238 {
239 for (i = 0; i < 8; i++)
240 for (j = 0; j < 4; j++)
241 *enc_ptr++ = bbox[i][j];
242
243 memcpy(movie->bbox, bbox, sizeof(movie->bbox));
244 }
245
246 /* -------------------------------------------------------------------- */
247 /* If we can send a row-delta map, go find which rows are repeats */
248 /* from the previous frame. */
249 /* -------------------------------------------------------------------- */
250 if (send_frame && rowdlt_ok)
251 {
252 memset(rowdlt, 0, sizeof(rowdlt)); /* zero out repeat bitmap. */
253 for (yi = yo = 0; yi < movie->y_dim; yi++)
254 {
255 if (memcmp(movie->vid + (yi*movie->x_dim),
256 vid + (yi*movie->x_dim), movie->x_dim) == 0)
257 {
258 rowdlt[yi >> 5] |= 1u << (yi & 0x1F);
259 enc_height_rd--;
260 movie->rpt_rows++;
261 } else
262 {
263 memcpy(enc_vid2 + yo * movie->x_dim,
264 vid + yi * movie->x_dim, movie->x_dim);
265 yo++;
266 }
267 }
268 assert( !send_rowdlt || yo < yi );
269 assert(!(send_rowdlt && yo == yi));
270 assert(yo > 0);
271 assert(enc_height_rd > 0);
272 assert(yo == enc_height_rd);
273
274 /* ---------------------------------------------------------------- */
275 /* Only send rowdelta if at least 2 rows are repeats. */
276 /* ---------------------------------------------------------------- */
277 if (enc_height - enc_height_rd > 2)
278 {
279 send_rowdlt = 1;
280 evid = enc_vid2;
281 enc_height = enc_height_rd;
282 /*printf("Frame %-6d %.8X %.8X %.8X %.8X %.8X\n", movie->fr, rowdlt[0], rowdlt[1], rowdlt[2], rowdlt[3], rowdlt[4]);*/
283
284 for (i = 0; i < movie->y_dim; i += 8)
285 {
286 j = 8 * ((i >> 3) & 3);
287 *enc_ptr++ = (rowdlt[i >> 5] >> j) & 0xFF;
288 }
289 } else
290 {
291 send_rowdlt = 0;
292 enc_height_rd = movie->y_dim;
293 }
294 }
295
296 /* -------------------------------------------------------------------- */
297 /* At this point we don't need the previous frame any more, so update */
298 /* -------------------------------------------------------------------- */
299 if (send_frame)
300 memcpy(movie->vid, vid, movie->x_dim * movie->y_dim);
301
302 /* -------------------------------------------------------------------- */
303 /* If we're sending the frame, copy it to our encoding buffer. Look */
304 /* for redundant rows as we go. */
305 /* -------------------------------------------------------------------- */
306 if (send_frame && enc_height_rd > 1)
307 {
308 memset(rowrpt, 0, sizeof(rowrpt)); /* zero out repeat bitmap. */
309 memcpy(enc_vid, evid, movie->x_dim); /* copy first row */
310 for (yi = 1, yo = 1; yi < enc_height_rd; yi++)
311 {
312 if (!memcmp(evid + (yi-1) * movie->x_dim,
313 evid + yi * movie->x_dim, movie->x_dim))
314 {
315 rowrpt[yi >> 5] |= 1u << (yi & 0x1F);
316
317 send_rowrpt = 1;
318 enc_height--;
319 movie->rpt_rows++;
320 } else
321 {
322 memcpy(enc_vid + yo * movie->x_dim,
323 evid + yi * movie->x_dim, movie->x_dim);
324 yo++;
325 }
326 }
327 assert( !send_rowrpt || yo < yi );
328 assert(!(send_rowrpt && yo == yi));
329
330 if (send_rowrpt)
331 {
332 for (i = 0; i < enc_height_rd; i += 8)
333 {
334 j = 8 * ((i >> 3) & 3);
335 *enc_ptr++ = (rowrpt[i >> 5] >> j) & 0xFF;
336 }
337 }
338 } else if (send_frame && enc_height_rd <= 1)
339 {
340 memcpy(enc_vid, enc_vid2, movie->x_dim * enc_height);
341 }
342
343 /*if (send_frame) printf("frame %.6X enc_height=%-3d enc_height_rd=%-3d\n", movie->fr, enc_height, enc_height_rd);*/
344
345 /* -------------------------------------------------------------------- */
346 /* If we're sending an image, try to RLE-compress it. If RLE "blows */
347 /* up" (expands the data) we'll send uncompressed. */
348 /* -------------------------------------------------------------------- */
349 if (send_frame)
350 {
351 uint8_t *rle_ptr = enc_ptr;
352 uint8_t *vid_ptr = enc_vid;
353 uint8_t *rle_end;
354 uint8_t *vid_end;
355 uint8_t *cpstart = enc_vid;
356 uint8_t p0, p1, p2, p3;
357
358 rle_max_len = (movie->x_dim * enc_height) >> 1;
359
360 vid_end = enc_vid + movie->x_dim * enc_height;
361 rle_end = enc_ptr + rle_max_len - 1;
362
363 /* ---------------------------------------------------------------- */
364 /* Keep encoding RLE until we either run out of pixels or we */
365 /* overflow the encoding buffer. We'll send uncompressed if RLE */
366 /* expands the image. */
367 /* ---------------------------------------------------------------- */
368 while (rle_ptr < rle_end && vid_ptr < vid_end)
369 {
370 int fl_len;
371 int fl_cur;
372 int remain = vid_end - vid_ptr;
373
374 /* ------------------------------------------------------------ */
375 /* Grab the next two pixels. */
376 /* If they're not equal append to a copy run. */
377 /* ------------------------------------------------------------ */
378 p0 = vid_ptr[0] & 0xF;
379 p1 = vid_ptr[1] & 0xF;
380
381 if (p0 != p1)
382 {
383 vid_ptr += 2;
384 continue;
385 }
386
387 /* ------------------------------------------------------------ */
388 /* See how long the run is. */
389 /* ------------------------------------------------------------ */
390 for (i = 2; i < remain; i += 2)
391 {
392 p2 = vid_ptr[i+0] & 0xF;
393 p3 = vid_ptr[i+1] & 0xF;
394
395 if (p2 != p0 || p3 != p0)
396 break;
397 }
398
399 fl_len = i >> 1; /* always even number, so div-by-2 */
400
401 /* ------------------------------------------------------------ */
402 /* If it's not a long enough run, just append them to the */
403 /* copy run and continue. */
404 /* ------------------------------------------------------------ */
405 if (fl_len == 1 && remain > 2)
406 {
407 vid_ptr += fl_len << 1;
408 continue;
409 }
410
411 /* ------------------------------------------------------------ */
412 /* Flush any existing copy run first. */
413 /* ------------------------------------------------------------ */
414 if (cpstart < vid_ptr)
415 {
416 int cp_len = vid_ptr - cpstart;
417 int cp_cur;
418
419 assert((cp_len & 1) == 0);
420
421 /* -------------------------------------------------------- */
422 /* Don't let copy run overflow buffer! */
423 /* -------------------------------------------------------- */
424 if (rle_ptr + 2 + (cp_len>>8) + (cp_len>>1) >= rle_end)
425 goto no_rle;
426
427 /* -------------------------------------------------------- */
428 /* Output the copy run. */
429 /* -------------------------------------------------------- */
430 while (cp_len > 0)
431 {
432 int p;
433 cp_cur = cp_len > 256 ? 256 : cp_len;
434 cp_len -= cp_cur;
435
436 *rle_ptr++ = cp_cur - 2;
437 for (j = 0; j < cp_cur; j += 2)
438 {
439 p = (cpstart[0] & 0xF) | ((cpstart[1]&0xF)<<4);
440 *rle_ptr++ = p;
441 cpstart += 2;
442 }
443 }
444 assert(cpstart == vid_ptr);
445 }
446
447 /* ------------------------------------------------------------ */
448 /* Advance the input video pointer beyond fill run. That */
449 /* location also marks the beginning of the next copy run. */
450 /* ------------------------------------------------------------ */
451 vid_ptr += fl_len << 1;
452 cpstart = vid_ptr;
453
454 /* ------------------------------------------------------------ */
455 /* Now output the RLE run. */
456 /* ------------------------------------------------------------ */
457 while (fl_len > 0)
458 {
459 fl_cur = fl_len > 263 ? 263 : fl_len;
460 fl_len -= fl_cur;
461
462 if (fl_cur < 8)
463 {
464 if (rle_ptr >= rle_end)
465 goto no_rle;
466 *rle_ptr++ = 1 | (fl_cur << 1) | (p0 << 4);
467 } else
468 {
469 if (rle_ptr + 1 >= rle_end)
470 goto no_rle;
471 *rle_ptr++ = 1 | (p0 << 4);
472 *rle_ptr++ = fl_cur - 8;
473 }
474 }
475 }
476
477 if (rle_ptr >= rle_end)
478 goto no_rle;
479
480 /* ---------------------------------------------------------------- */
481 /* Flush any copy run at end. */
482 /* ---------------------------------------------------------------- */
483 if (cpstart < vid_ptr)
484 {
485 int cp_len = vid_ptr - cpstart;
486 int cp_cur;
487
488 assert((cp_len & 1) == 0);
489
490 /* ------------------------------------------------------------ */
491 /* Don't let copy run overflow buffer! */
492 /* ------------------------------------------------------------ */
493 if (rle_ptr + 2 + (cp_len>>8) + (cp_len>>1) >= rle_end)
494 goto no_rle;
495
496 /* ------------------------------------------------------------ */
497 /* Output the copy run. */
498 /* ------------------------------------------------------------ */
499 while (cp_len > 0)
500 {
501 int p;
502 cp_cur = cp_len > 256 ? 256 : cp_len;
503 cp_len -= cp_cur;
504
505 *rle_ptr++ = cp_cur - 2;
506 for (j = 0; j < cp_cur; j += 2)
507 {
508 p = (cpstart[0] & 0xF) | ((cpstart[1]&0xF)<<4);
509 *rle_ptr++ = p;
510 cpstart += 2;
511 }
512 }
513 assert(cpstart == vid_ptr);
514 }
515
516 /* ---------------------------------------------------------------- */
517 /* If we make it to here w/out overflowing the RLE buf, send RLE. */
518 /* ---------------------------------------------------------------- */
519 if (rle_ptr <= rle_end)
520 {
521 send_rle = 1;
522 enc_ptr = rle_ptr;
523 }
524 } /* end of RLE encode */
525
526 no_rle:
527
528 /* -------------------------------------------------------------------- */
529 /* If we're sending the frame and RLE didn't work out, send packed. */
530 /* -------------------------------------------------------------------- */
531 if (send_frame && !send_rle)
532 {
533 int total = movie->x_dim * enc_height;
534
535 for (i = 0; i < total; i += 2)
536 {
537 *enc_ptr++ = (enc_vid[i + 0] & 0xF)
538 | ((enc_vid[i + 1] & 0xF) << 4);
539 }
540 }
541
542 #ifndef NO_LZO
543 /* -------------------------------------------------------------------- */
544 /* Try to compress the encoded frame with LZO. */
545 /* -------------------------------------------------------------------- */
546 if (lzo_wrk && lzo_tmp && enc_ptr > enc_hdr + 8)
547 {
548 int r;
549 lzo_uint lzo_len = 0, data_len = enc_ptr - enc_hdr - 8;
550
551 r = lzo1x_1_compress(enc_hdr + 8, data_len,
552 lzo_tmp, &lzo_len, (lzo_voidp)lzo_wrk);
553
554 if (r == LZO_E_OK && lzo_len < data_len && lzo_len > 0)
555 {
556 memcpy(enc_hdr + 8, lzo_tmp, lzo_len);
557 enc_ptr = enc_hdr + 8 + lzo_len;
558 lzo_comp = 1;
559 movie->tot_lzosave += data_len - lzo_len;
560 }
561 }
562 #endif
563
564 /* -------------------------------------------------------------------- */
565 /* Generate the header byte. */
566 /* -------------------------------------------------------------------- */
567 if ( send_frame ) header_byte |= FLG_FRSENT;
568 if ( send_bbox ) header_byte |= FLG_BBSENT;
569 if ( send_rowrpt) header_byte |= FLG_RPTMAP;
570 if ( send_rle ) header_byte |= FLG_RLECMP;
571 if ( send_rowdlt) header_byte |= FLG_DLTMAP;
572 if ( lzo_comp ) header_byte |= FLG_LZOCMP;
573
574 /* -------------------------------------------------------------------- */
575 /* Prepend the header: Frame # and flag byte. */
576 /* -------------------------------------------------------------------- */
577 enc_hdr[0] = ((enc_ptr - enc_hdr) >> 0) & 0xFF;
578 enc_hdr[1] = ((enc_ptr - enc_hdr) >> 8) & 0xFF;
579 enc_hdr[2] = ((enc_ptr - enc_hdr) >> 16) & 0xFF;
580 enc_hdr[3] = ((enc_ptr - enc_hdr) >> 24) & 0xFF;
581 enc_hdr[4] = (movie->fr >> 0) & 0xFF;
582 enc_hdr[5] = (movie->fr >> 8) & 0xFF;
583 enc_hdr[6] = (movie->fr >> 16) & 0xFF;
584 enc_hdr[7] = header_byte;
585
586 /* -------------------------------------------------------------------- */
587 /* Send it all in one big fwrite. */
588 /* -------------------------------------------------------------------- */
589 fwrite(enc_buf, 1, enc_ptr - enc_buf, movie->f);
590 fflush(movie->f);
591 movie->tot_bytes += enc_ptr - enc_buf;
592
593 movie->fr++; /* increment frame count. */
594 }
595
596
597 /* ======================================================================== */
598 /* MVI_RD_FRAME -- Reads a frame from a movie file and decodes it. */
599 /* ======================================================================== */
mvi_rd_frame(mvi_t * movie,uint8_t * vid,uint8_t bbox[8][4])600 int mvi_rd_frame(mvi_t *movie, uint8_t *vid, uint8_t bbox[8][4])
601 {
602 int got_frame = 0;
603 int got_bbox = 0;
604 int got_rowrpt = 0;
605 int got_rle = 0;
606 int got_rowdlt = 0;
607 int lzo_comp = 0;
608 uint8_t *dec_ptr = enc_buf, *dec_end;
609 uint8_t *dec_vid;
610 uint8_t *dvid;
611 size_t tot_rd;
612 uint32_t flags;
613 int i, j;
614 int enc_height, enc_height_rd;
615 uint32_t fr_len;
616
617 /* -------------------------------------------------------------------- */
618 /* Sanity check. */
619 /* -------------------------------------------------------------------- */
620 if (!movie->f) return -1; /* no current file? */
621
622 again:
623 /* -------------------------------------------------------------------- */
624 /* Read 8 bytes. It's either a frame header or a file header. */
625 /* -------------------------------------------------------------------- */
626 tot_rd = fread(enc_buf, 1, 8, movie->f);
627 if (tot_rd < 8)
628 return -1; /* end of file or other error */
629
630
631 /* -------------------------------------------------------------------- */
632 /* Check for a file header on this frame. */
633 /* -------------------------------------------------------------------- */
634 if (tot_rd == 8 &&
635 enc_buf[0] == 0x4A && enc_buf[1] == 0x5A &&
636 enc_buf[2] == 0x6A && enc_buf[3] == 0x7A)
637 {
638 int new_x_dim, new_y_dim;
639
640 new_x_dim = (enc_buf[5] << 8) | enc_buf[4];
641 new_y_dim = (enc_buf[7] << 8) | enc_buf[6];
642
643 if (new_x_dim != movie->x_dim ||
644 new_y_dim != movie->y_dim)
645 {
646 movie->x_dim = new_x_dim;
647 movie->y_dim = new_y_dim;
648 if (new_x_dim > MVI_MAX_X || new_y_dim > MVI_MAX_Y)
649 {
650 fprintf(stderr, "MVI_RD: Movie size %dx%d too large!",
651 new_x_dim, new_y_dim);
652 return -1;
653 }
654 }
655
656 goto again; /* loop until we get a frame header */
657 }
658
659 /* -------------------------------------------------------------------- */
660 /* Pull apart the frame header. */
661 /* -------------------------------------------------------------------- */
662 fr_len = (enc_buf[0] << 0) |
663 (enc_buf[1] << 8) |
664 (enc_buf[2] << 16) |
665 (enc_buf[3] << 24);
666
667 if (fr_len > ENC_BUF_SZ)
668 {
669 fprintf(stderr,
670 "MVI_RD: Frame size too large: %d bytes (%.8X bytes)\n",
671 fr_len, fr_len);
672 exit(1);
673 }
674
675 movie->last_fr = movie->fr;
676
677 movie->fr = (enc_buf[4] << 0) |
678 (enc_buf[5] << 8) |
679 (enc_buf[6] << 16);
680
681 flags = enc_buf[7];
682
683
684 got_frame = flags & FLG_FRSENT;
685 got_bbox = flags & FLG_BBSENT;
686 got_rowrpt = flags & FLG_RPTMAP;
687 got_rle = flags & FLG_RLECMP;
688 got_rowdlt = flags & FLG_DLTMAP;
689 lzo_comp = flags & FLG_LZOCMP;
690
691 /* -------------------------------------------------------------------- */
692 /* Now read the rest of the frame. */
693 /* -------------------------------------------------------------------- */
694 tot_rd += fread(enc_buf, 1, fr_len - 8, movie->f);
695 dec_end = enc_buf + fr_len - 8;
696 dec_ptr = enc_buf;
697
698 if (tot_rd != fr_len)
699 {
700 fprintf(stderr,
701 "MVI_RD: Short read on frame %d (%d vs %d bytes)\n"
702 " Previous frame was frame %d\n",
703 movie->fr, (int)tot_rd, fr_len, movie->last_fr);
704 exit(1);
705 }
706
707
708 /* -------------------------------------------------------------------- */
709 /* Sanity check flags. */
710 /* -------------------------------------------------------------------- */
711 if ((flags & 0xC0) != 0 ||
712 (got_rle != 0 && got_frame == 0) ||
713 (got_rowdlt != 0 && got_frame == 0) ||
714 (got_rowrpt != 0 && got_frame == 0))
715 {
716 fprintf(stderr, "MVI_RD: Bogus flags: %.2X\n", flags);
717 return -1;
718 }
719
720 if (flags != 0 && (movie->x_dim == 0 || movie->y_dim == 0))
721 {
722 fprintf(stderr, "MVI_RD: Movie data before valid file header!\n");
723 return -1;
724 }
725
726
727 /* -------------------------------------------------------------------- */
728 /* If the frame is LZO compressed, decompress it before proceeding. */
729 /* -------------------------------------------------------------------- */
730 #ifdef NO_LZO
731 if (lzo_comp)
732 {
733 fprintf(stderr, "MVI_RD: This movie is LZO-compressed. LZO "
734 "compression support is not compiled in.\n");
735 return -1;
736 }
737 #else
738 if (lzo_comp)
739 {
740 int r;
741 lzo_uint lzo_len = 0;
742
743 if (!lzo_tmp)
744 {
745 fprintf(stderr, "MVI_RD: This movie is LZO-compressed, but "
746 "there is insufficient memory for decompresion\n");
747 return -1;
748 }
749
750 r = lzo1x_decompress(dec_ptr, fr_len - 8, lzo_tmp,
751 &lzo_len,
752 (lzo_voidp)NULL);
753
754 if (r == LZO_E_OK)
755 {
756 memcpy(dec_ptr, lzo_tmp, lzo_len);
757 fr_len = 8 + lzo_len;
758 dec_end = dec_ptr + lzo_len;
759 } else
760 {
761 fprintf(stderr, "MVI_RD: LZO error: %d\n", r);
762 return -1;
763 }
764 }
765 #endif
766
767 /* -------------------------------------------------------------------- */
768 /* If we have an updated set of bounding boxes, read them in. */
769 /* -------------------------------------------------------------------- */
770 if (got_bbox)
771 {
772 for (i = 0; i < 8; i++)
773 for (j = 0; j < 4; j++)
774 movie->bbox[i][j] = *dec_ptr++;
775 }
776
777 /* -------------------------------------------------------------------- */
778 /* If we have a row-delta map, read that in. */
779 /* -------------------------------------------------------------------- */
780 memset(rowdlt, 0, sizeof(rowdlt));
781 enc_height_rd = movie->y_dim;
782
783 if (got_rowdlt)
784 {
785 for (i = 0; i < movie->y_dim; i += 8)
786 rowdlt[i >> 5] |= *dec_ptr++ << (8*((i>>3) & 3));
787
788 if (dec_ptr >= dec_end)
789 {
790 fprintf(stderr, "MVI_RD: Error reading row-repeat tbl\n");
791 return -1;
792 }
793
794 for (i = 0; i < movie->y_dim; i += 32)
795 {
796 uint32_t tmp = rowdlt[i >> 5];
797
798 while (tmp)
799 {
800 tmp &= tmp - 1;
801 enc_height_rd--;
802 }
803 }
804 }
805
806 /* -------------------------------------------------------------------- */
807 /* If we have a row-repeat map, read that in. */
808 /* -------------------------------------------------------------------- */
809 memset(rowrpt, 0, sizeof(rowrpt));
810 enc_height = enc_height_rd;
811
812 if (got_rowrpt)
813 {
814 for (i = 0; i < enc_height_rd; i += 8)
815 rowrpt[i >> 5] |= *dec_ptr++ << (8*((i>>3) & 3));
816
817 if (dec_ptr >= dec_end)
818 {
819 fprintf(stderr, "MVI_RD: Error reading row-repeat tbl\n");
820 return -1;
821 }
822
823 for (i = 0; i < enc_height_rd; i += 32)
824 {
825 uint32_t tmp = rowrpt[i >> 5];
826
827 while (tmp)
828 {
829 tmp &= tmp - 1;
830 enc_height--;
831 }
832 }
833 }
834
835 /* -------------------------------------------------------------------- */
836 /* Now decode the image (prior to unpacking the row repeat map). */
837 /* -------------------------------------------------------------------- */
838 dec_vid = got_rowrpt ? enc_vid :
839 got_rowdlt ? enc_vid2 : vid;
840
841 if (got_frame == 0)
842 {
843 memcpy(vid, movie->vid, movie->x_dim * movie->y_dim);
844 } else if (!got_rle)
845 {
846 for (i = 0; i < movie->x_dim * enc_height; i += 2)
847 {
848 *dec_vid++ = 0xF & *dec_ptr;
849 *dec_vid++ = 0xF & (*dec_ptr >> 4);
850 dec_ptr++;
851 }
852 } else /* RLE data */
853 {
854 int run, len, p;
855 int remain = movie->x_dim * enc_height;
856
857 /* ---------------------------------------------------------------- */
858 /* Expand all the runs in the encoded image. The ending comes */
859 /* implicitly when no images pixels remain. */
860 /* ---------------------------------------------------------------- */
861 while (remain > 0)
862 {
863 if (dec_ptr >= dec_end)
864 {
865 fprintf(stderr, "MVI_RD: Error in RLE data!\n");
866 return -1;
867 }
868
869 run = *dec_ptr++;
870
871 /* ------------------------------------------------------------ */
872 /* Handle copy runs by unpacking and copying the pixels to */
873 /* the output. */
874 /* ------------------------------------------------------------ */
875 if ((run & 1) == 0) /* copy run? */
876 {
877 len = run + 2;
878 if (len > remain || (dec_ptr + (len>>1)) > dec_end)
879 {
880 fprintf(stderr, "MVI_RD: Error in RLE data!\n");
881 return -1;
882 }
883 remain -= len;
884
885 for (i = 0; i < len; i += 2)
886 {
887 *dec_vid++ = 0xF & *dec_ptr;
888 *dec_vid++ = 0xF & (*dec_ptr >> 4);
889 dec_ptr++;
890 }
891
892 continue;
893 }
894
895 /* ------------------------------------------------------------ */
896 /* Handle fill runs by writing the color value over and over. */
897 /* ------------------------------------------------------------ */
898 len = run & 0xE;
899 if (!len) len = 16 + (*dec_ptr++ << 1);
900
901 if (len > remain || dec_ptr > dec_end)
902 {
903 fprintf(stderr, "MVI_RD: Error in RLE data!\n");
904 return -1;
905 }
906 remain -= len;
907
908 p = (run & 0xF0) >> 4;
909
910 len >>= 1;
911
912 while (len-->0) { *dec_vid++ = p; *dec_vid++ = p; }
913 }
914
915 if (remain != 0)
916 {
917 fprintf(stderr, "MVI_RD: Error in RLE data!\n");
918 return -1;
919 }
920 }
921
922 /* -------------------------------------------------------------------- */
923 /* If we have a row-repeat map, expand vertically-compressed image. */
924 /* -------------------------------------------------------------------- */
925 if (got_rowrpt)
926 {
927 int yo, yi, xd = movie->x_dim;
928
929 dvid = got_rowdlt ? enc_vid2 : vid;
930
931 yi = enc_height - 1;
932 for (yo = enc_height_rd - 1; yo >= 0; yo--)
933 {
934 memcpy(dvid + yo*xd, enc_vid + yi*xd, xd);
935
936 if ((1 & (rowrpt[yo >> 5] >> (yo & 0x1F))) == 0) /* not a rpt */
937 yi--;
938 }
939
940 assert(yi == -1);
941 }
942
943 /* -------------------------------------------------------------------- */
944 /* If we have a row-delta map, expand temporally-compressed image. */
945 /* -------------------------------------------------------------------- */
946 if (got_rowdlt)
947 {
948 int yo, yi, xd = movie->x_dim;
949
950 yi = enc_height_rd - 1;
951 for (yo = movie->y_dim - 1; yo >= 0; yo--)
952 {
953 if ((1 & (rowdlt[yo >> 5] >> (yo & 0x1F))) == 0) /* not a rpt */
954 {
955 memcpy(vid + yo*xd, enc_vid2 + yi*xd, xd);
956 yi--;
957 } else /* copy from previous frame */
958 {
959 memcpy(vid + yo*xd, movie->vid + yo*xd, xd);
960 }
961 }
962
963 assert(yi == -1);
964 }
965
966 /* -------------------------------------------------------------------- */
967 /* Remember each frame we decode. */
968 /* -------------------------------------------------------------------- */
969 if (got_frame)
970 memcpy(movie->vid, vid, movie->x_dim * movie->y_dim);
971
972
973 /* -------------------------------------------------------------------- */
974 /* Copy over current bounding boxes. */
975 /* -------------------------------------------------------------------- */
976 memcpy(bbox, movie->bbox, sizeof(movie->bbox));
977
978 return (got_frame ? 0 : MVI_FR_SAME) |
979 (got_bbox ? 0 : MVI_BB_SAME);
980 }
981
982 /* ======================================================================== */
983 /* This program is free software; you can redistribute it and/or modify */
984 /* it under the terms of the GNU General Public License as published by */
985 /* the Free Software Foundation; either version 2 of the License, or */
986 /* (at your option) any later version. */
987 /* */
988 /* This program is distributed in the hope that it will be useful, */
989 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
990 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
991 /* General Public License for more details. */
992 /* */
993 /* You should have received a copy of the GNU General Public License along */
994 /* with this program; if not, write to the Free Software Foundation, Inc., */
995 /* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
996 /* ======================================================================== */
997 /* Copyright (c) 1998-2005, Joseph Zbiciak */
998 /* ======================================================================== */
999
1000