comparison libmpcodecs/native/roqav.c @ 5602:628c85c15c7b

moved to libmpcodecs/native/
author arpi
date Sat, 13 Apr 2002 18:03:02 +0000
parents roqav.c@11f440fa5ee9
children 47daf6075bc6
comparison
equal deleted inserted replaced
5601:fd85802f755b 5602:628c85c15c7b
1 /*
2 RoQ A/V decoder for the MPlayer program
3 by Mike Melanson
4 based on Dr. Tim Ferguson's RoQ document and accompanying source
5 code found at:
6 http://www.csse.monash.edu.au/~timf/videocodec.html
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include "config.h"
12 #include "bswap.h"
13 #include "mp_msg.h"
14 #include "mp_image.h"
15
16 #define LE_16(x) (le2me_16(*(unsigned short *)(x)))
17 #define LE_32(x) (le2me_32(*(unsigned int *)(x)))
18
19 #define CLAMP_S16(x) if (x < -32768) x = -32768; \
20 else if (x > 32767) x = 32767;
21 #define SE_16BIT(x) if (x & 0x8000) x -= 0x10000;
22
23 // RoQ chunk types
24 #define RoQ_INFO 0x1001
25 #define RoQ_QUAD_CODEBOOK 0x1002
26 #define RoQ_QUAD_VQ 0x1011
27 #define RoQ_SOUND_MONO 0x1020
28 #define RoQ_SOUND_STEREO 0x1021
29
30 #define MAX_ROQ_CODEBOOK_SIZE 256
31
32 // codebook entry for 2x2 vector
33 typedef struct
34 {
35 // upper and lower luminance value pairs of 2x2 vector: [y0 y1], [y2 y3]
36 unsigned short v2_y_u;
37 unsigned short v2_y_l;
38
39 // chrominance components
40 unsigned char u, v;
41
42 // these variables are for rendering a doublesized 8x8 block; e.g.:
43 // v2_y_rows12 = [y0 y0 y1 y1]
44 // v2_y_rows34 = [y2 y2 y3 y3]
45 unsigned long v2d_y_rows_12;
46 unsigned long v2d_y_rows_34;
47 // ex: v2_u_row1 = [u u]
48 // v2_v_row2 = [v v]
49 unsigned short v2d_u_rows_12;
50 unsigned short v2d_v_rows_12;
51
52 // maintain separate bytes for the luminance values as well
53 unsigned char y0, y1, y2, y3;
54 } roq_v2_codebook;
55
56 // codebook entry for 4x4 vector
57 typedef struct
58 {
59 unsigned char v2_index[4];
60 } roq_v4_codebook;
61
62 typedef struct
63 {
64 roq_v2_codebook v2[MAX_ROQ_CODEBOOK_SIZE];
65 roq_v4_codebook v4[MAX_ROQ_CODEBOOK_SIZE];
66 mp_image_t *prev_frame;
67 } roqvideo_info;
68
69
70 // This function fills in the missing information for a v2 vector after
71 // loading the Y, U and V values.
72 inline void prep_v2(roq_v2_codebook *v2)
73 {
74 v2->v2_y_u = be2me_16((v2->y0 << 8) | v2->y1);
75 v2->v2_y_l = be2me_16((v2->y2 << 8) | v2->y3);
76
77 v2->v2d_y_rows_12 = be2me_32((v2->y0 << 24) | (v2->y0 << 16) |
78 (v2->y1 << 8) | v2->y1);
79 v2->v2d_y_rows_34 = be2me_32((v2->y2 << 24) | (v2->y2 << 16) |
80 (v2->y3 << 8) | v2->y3);
81
82 // no reason to swap these for endianness since they're the same bytes
83 v2->v2d_u_rows_12 = (v2->u << 8) | v2->u;
84 v2->v2d_v_rows_12 = (v2->v << 8) | v2->v;
85 }
86
87 inline void paint_v2double_block(
88 unsigned char *y_plane,
89 unsigned char *u_plane,
90 unsigned char *v_plane,
91 roq_v2_codebook *v2,
92 unsigned int y_stride,
93 unsigned int u_stride,
94 unsigned int v_stride)
95 {
96 // render the luminance components
97 *(unsigned int *)y_plane = v2->v2d_y_rows_12;
98 y_plane += y_stride;
99 *(unsigned int *)y_plane = v2->v2d_y_rows_12;
100 y_plane += y_stride;
101 *(unsigned int *)y_plane = v2->v2d_y_rows_34;
102 y_plane += y_stride;
103 *(unsigned int *)y_plane = v2->v2d_y_rows_34;
104
105 // render the color planes
106 *(unsigned short *)u_plane = v2->v2d_u_rows_12;
107 u_plane += u_stride;
108 *(unsigned short *)u_plane = v2->v2d_u_rows_12;
109
110 *(unsigned short *)v_plane = v2->v2d_v_rows_12;
111 v_plane += v_stride;
112 *(unsigned short *)v_plane = v2->v2d_v_rows_12;
113 }
114
115 inline void paint_v4_block(
116 unsigned char *y_plane,
117 unsigned char *u_plane,
118 unsigned char *v_plane,
119 unsigned int y_stride,
120 unsigned int u_stride,
121 unsigned int v_stride,
122 roq_v2_codebook *v2_a,
123 roq_v2_codebook *v2_b,
124 roq_v2_codebook *v2_c,
125 roq_v2_codebook *v2_d)
126 {
127 // render luminance components
128 ((unsigned short *)y_plane)[0] = v2_a->v2_y_u;
129 ((unsigned short *)y_plane)[1] = v2_b->v2_y_u;
130
131 y_plane += y_stride;
132 ((unsigned short *)y_plane)[0] = v2_a->v2_y_l;
133 ((unsigned short *)y_plane)[1] = v2_b->v2_y_l;
134
135 y_plane += y_stride;
136 ((unsigned short *)y_plane)[0] = v2_c->v2_y_u;
137 ((unsigned short *)y_plane)[1] = v2_d->v2_y_u;
138
139 y_plane += y_stride;
140 ((unsigned short *)y_plane)[0] = v2_c->v2_y_l;
141 ((unsigned short *)y_plane)[1] = v2_d->v2_y_l;
142
143 // render the color planes
144 u_plane[0] = v2_a->u;
145 u_plane[1] = v2_b->u;
146 u_plane += u_stride;
147 u_plane[0] = v2_c->u;
148 u_plane[1] = v2_d->u;
149
150 v_plane[0] = v2_a->v;
151 v_plane[1] = v2_b->v;
152 v_plane += v_stride;
153 v_plane[0] = v2_c->v;
154 v_plane[1] = v2_d->v;
155 }
156
157 // This function copies the 4x4 block from the prev_*_planes to the
158 // current *_planes.
159 inline void copy_4x4_block(
160 unsigned char *y_plane,
161 unsigned char *u_plane,
162 unsigned char *v_plane,
163 unsigned char *prev_y_plane,
164 unsigned char *prev_u_plane,
165 unsigned char *prev_v_plane,
166 unsigned int y_stride,
167 unsigned int u_stride,
168 unsigned int v_stride)
169 {
170 int i;
171
172 // copy over the luminance components (4 rows, 1 uint each)
173 for (i = 0; i < 4; i++)
174 {
175 *(unsigned int *)y_plane = *(unsigned int *)prev_y_plane;
176 y_plane += y_stride;
177 prev_y_plane += y_stride;
178 }
179
180 // copy the chrominance values
181 for (i = 0; i < 2; i++)
182 {
183 *(unsigned short*)u_plane = *(unsigned short*)prev_u_plane;
184 u_plane += u_stride;
185 prev_u_plane += u_stride;
186 *(unsigned short*)v_plane = *(unsigned short*)prev_v_plane;
187 v_plane += v_stride;
188 prev_v_plane += v_stride;
189 }
190 }
191
192 // This function copies the 8x8 block from the prev_*_planes to the
193 // current *_planes.
194 inline void copy_8x8_block(
195 unsigned char *y_plane,
196 unsigned char *u_plane,
197 unsigned char *v_plane,
198 unsigned char *prev_y_plane,
199 unsigned char *prev_u_plane,
200 unsigned char *prev_v_plane,
201 unsigned int y_stride,
202 unsigned int u_stride,
203 unsigned int v_stride)
204 {
205 int i;
206
207 // copy over the luminance components (8 rows, 2 uints each)
208 for (i = 0; i < 8; i++)
209 {
210 ((unsigned int *)y_plane)[0] = ((unsigned int *)prev_y_plane)[0];
211 ((unsigned int *)y_plane)[1] = ((unsigned int *)prev_y_plane)[1];
212 y_plane += y_stride;
213 prev_y_plane += y_stride;
214 }
215
216 // copy the chrominance values
217 for (i = 0; i < 4; i++)
218 {
219 *(unsigned int*)u_plane = *(unsigned int*)prev_u_plane;
220 u_plane += u_stride;
221 prev_u_plane += u_stride;
222 *(unsigned int*)v_plane = *(unsigned int*)prev_v_plane;
223 v_plane += v_stride;
224 prev_v_plane += v_stride;
225 }
226 }
227
228 // This function creates storage space for the vector codebooks.
229 void *roq_decode_video_init(void)
230 {
231 roqvideo_info *info =
232 (roqvideo_info *)calloc(sizeof(roqvideo_info), 1);
233
234 info->prev_frame = NULL;
235
236 return info;
237 }
238
239 #define EMPTY_ROQ_CODEWORD 0xFFFF0000
240
241 #define FETCH_NEXT_CODE() \
242 if (current_roq_codeword == EMPTY_ROQ_CODEWORD) \
243 { \
244 if (stream_ptr + 2 > encoded_size) \
245 { \
246 mp_msg(MSGT_DECVIDEO, MSGL_WARN, \
247 "RoQ video: stream pointer just went out of bounds (1)\n"); \
248 return; \
249 } \
250 current_roq_codeword = (0x0000FFFF) | \
251 (encoded[stream_ptr + 0] << 16) | \
252 (encoded[stream_ptr + 1] << 24); \
253 stream_ptr += 2; \
254 } \
255 roq_code = ((current_roq_codeword >> 30) & 0x03); \
256 current_roq_codeword <<= 2;
257
258 #define FETCH_NEXT_ARGUMENT() \
259 if (stream_ptr + 1 > encoded_size) \
260 { \
261 mp_msg(MSGT_DECVIDEO, MSGL_WARN, \
262 "RoQ video: stream pointer just went out of bounds (2)\n"); \
263 return; \
264 } \
265 argument = encoded[stream_ptr++];
266
267 #define CHECK_PREV_FRAME() \
268 if (!info->prev_frame) \
269 { \
270 mp_msg(MSGT_DECVIDEO, MSGL_WARN, \
271 "RoQ video: can't handle motion vector when there's no previous frame\n"); \
272 return; \
273 }
274
275 void roq_decode_video(void *context, unsigned char *encoded,
276 int encoded_size, mp_image_t *mpi)
277 {
278 roqvideo_info *info = (roqvideo_info *)context;
279
280 int stream_ptr = 0;
281 int i, j;
282 int chunk_length;
283 int v2_count;
284 int v4_count;
285
286 int roq_code;
287 unsigned int current_roq_codeword = EMPTY_ROQ_CODEWORD;
288 unsigned char argument = 0;
289 char mean_motion_x;
290 char mean_motion_y;
291 int mx, my; // for calculating the motion vector
292
293 int mblock_x = 0;
294 int mblock_y = 0;
295 int quad8_x, quad8_y; // for pointing to 8x8 blocks in a macroblock
296 int quad4_x, quad4_y; // for pointing to 4x4 blocks in an 8x8 block
297
298 unsigned char *y_plane;
299 unsigned char *u_plane;
300 unsigned char *v_plane;
301 unsigned char *prev_y_plane;
302 unsigned char *prev_u_plane;
303 unsigned char *prev_v_plane;
304 unsigned int y_stride = mpi->stride[0];
305 unsigned int u_stride = mpi->stride[1];
306 unsigned int v_stride = mpi->stride[2];
307
308 roq_v4_codebook v4;
309
310 // make sure the encoded chunk is of minimal acceptable length
311 if (encoded_size < 8)
312 {
313 mp_msg(MSGT_DECVIDEO, MSGL_WARN,
314 "RoQ video: chunk isn't even 8 bytes long (minimum acceptable length)\n");
315 return;
316 }
317
318 // make sure the resolution checks out
319 if ((mpi->width % 16 != 0) || (mpi->height % 16 != 0))
320 {
321 mp_msg(MSGT_DECVIDEO, MSGL_WARN,
322 "RoQ video resolution: %d x %d; expected dimensions divisible by 16\n");
323 return;
324 }
325
326 if (LE_16(&encoded[stream_ptr]) == RoQ_QUAD_CODEBOOK)
327 {
328 stream_ptr += 2;
329 chunk_length = LE_32(&encoded[stream_ptr]);
330 stream_ptr += 4;
331 v4_count = encoded[stream_ptr++];
332 v2_count = encoded[stream_ptr++];
333 if (v2_count == 0)
334 v2_count = 256;
335 if ((v4_count == 0) && (v2_count * 6 < chunk_length))
336 v4_count = 256;
337
338 // make sure the lengths agree with each other
339 if (((v2_count * 6) + (v4_count * 4)) != chunk_length)
340 {
341 mp_msg(MSGT_DECVIDEO, MSGL_WARN,
342 "RoQ video: encountered quad codebook chunk with weird lengths (1)\n");
343 return;
344 }
345 if ((v2_count * 6) > (encoded_size - stream_ptr))
346 {
347 mp_msg(MSGT_DECVIDEO, MSGL_WARN,
348 "RoQ video: encountered quad codebook chunk with weird lengths (2)\n");
349 return;
350 }
351
352 // load the 2x2 vectors
353 for (i = 0; i < v2_count; i++)
354 {
355 info->v2[i].y0 = encoded[stream_ptr++];
356 info->v2[i].y1 = encoded[stream_ptr++];
357 info->v2[i].y2 = encoded[stream_ptr++];
358 info->v2[i].y3 = encoded[stream_ptr++];
359 info->v2[i].u = encoded[stream_ptr++];
360 info->v2[i].v = encoded[stream_ptr++];
361 prep_v2(&info->v2[i]);
362 }
363
364 if ((v4_count * 4) > (encoded_size - stream_ptr))
365 {
366 mp_msg(MSGT_DECVIDEO, MSGL_WARN,
367 "RoQ video: encountered quad codebook chunk with weird lengths (3)\n");
368 return;
369 }
370
371 // load the 4x4 vectors
372 for (i = 0; i < v4_count; i++)
373 {
374 info->v4[i].v2_index[0] = encoded[stream_ptr++];
375 info->v4[i].v2_index[1] = encoded[stream_ptr++];
376 info->v4[i].v2_index[2] = encoded[stream_ptr++];
377 info->v4[i].v2_index[3] = encoded[stream_ptr++];
378 }
379 }
380
381 if (LE_16(&encoded[stream_ptr]) == RoQ_QUAD_VQ)
382 {
383 stream_ptr += 2;
384 chunk_length = LE_32(&encoded[stream_ptr]);
385 stream_ptr += 4;
386 mean_motion_y = encoded[stream_ptr++];
387 mean_motion_x = encoded[stream_ptr++];
388
389 // start by copying entire previous frame
390 if (info->prev_frame)
391 {
392 memcpy(mpi->planes[0], info->prev_frame->planes[0],
393 mpi->width * mpi->height);
394 memcpy(mpi->planes[1], info->prev_frame->planes[1],
395 (mpi->width * mpi->height) / 4);
396 memcpy(mpi->planes[2], info->prev_frame->planes[2],
397 (mpi->width * mpi->height) / 4);
398 }
399
400 // iterate through the 16x16 macroblocks
401 for (mblock_y = 0; mblock_y < mpi->height; mblock_y += 16)
402 {
403 for (mblock_x = 0; mblock_x < mpi->width; mblock_x += 16)
404 {
405 // iterate through the 4 quadrants of the macroblock
406 for (i = 0; i < 4; i++)
407 {
408 quad8_x = mblock_x;
409 quad8_y = mblock_y;
410 if (i & 0x01) quad8_x += 8;
411 if (i & 0x02) quad8_y += 8;
412
413 // set up the planes
414 y_plane = mpi->planes[0] + quad8_y * y_stride + quad8_x;
415 u_plane = mpi->planes[1] + (quad8_y / 2) * u_stride + (quad8_x / 2);
416 v_plane = mpi->planes[2] + (quad8_y / 2) * v_stride + (quad8_x / 2);
417
418 // decide how to handle this 8x8 quad
419 FETCH_NEXT_CODE();
420 switch(roq_code)
421 {
422 // 8x8 block is the same as in the previous frame;
423 // skip it
424 case 0:
425 break;
426
427 // 8x8 block is painted with an 8x8 block from the last frame
428 // (i.e., motion compensation)
429 case 1:
430 CHECK_PREV_FRAME();
431
432 // prepare the pointers to the planes in the previous frame
433 FETCH_NEXT_ARGUMENT(); // argument contains motion vectors
434
435 // figure out the motion vectors
436 mx = quad8_x + 8 - (argument >> 4) - mean_motion_x;
437 my = quad8_y + 8 - (argument & 0x0F) - mean_motion_y;
438
439 prev_y_plane = info->prev_frame->planes[0] +
440 my * y_stride + mx;
441 prev_u_plane = info->prev_frame->planes[1] +
442 (my / 2) * u_stride + (mx + 1) / 2;
443 prev_v_plane = info->prev_frame->planes[2] +
444 (my / 2) * v_stride + (mx + 1) / 2;
445
446 // sanity check before rendering
447 copy_8x8_block(
448 y_plane,
449 u_plane,
450 v_plane,
451 prev_y_plane,
452 prev_u_plane,
453 prev_v_plane,
454 y_stride,
455 u_stride,
456 v_stride
457 );
458 break;
459
460 // 8x8 block is painted with a doublesized 4x4 vector
461 case 2:
462 FETCH_NEXT_ARGUMENT();
463 v4 = info->v4[argument];
464
465 // sanity check before rendering
466 // iterate through 4 4x4 blocks
467 for (j = 0; j < 4; j++)
468 {
469 quad4_x = quad8_x;
470 quad4_y = quad8_y;
471 if (j & 0x01) quad4_x += 4;
472 if (j & 0x02) quad4_y += 4;
473
474 // set up the planes
475 y_plane = mpi->planes[0] + quad4_y * y_stride + quad4_x;
476 u_plane = mpi->planes[1] +
477 (quad4_y / 2) * u_stride + (quad4_x / 2);
478 v_plane = mpi->planes[2] +
479 (quad4_y / 2) * v_stride + (quad4_x / 2);
480
481 paint_v2double_block(
482 y_plane,
483 u_plane,
484 v_plane,
485 &info->v2[v4.v2_index[j]],
486 y_stride,
487 u_stride,
488 v_stride
489 );
490 }
491 break;
492
493 // 8x8 block is broken down into 4 4x4 blocks and painted using
494 // 4 different codes.
495 case 3:
496 // iterate through 4 4x4 blocks
497 for (j = 0; j < 4; j++)
498 {
499 quad4_x = quad8_x;
500 quad4_y = quad8_y;
501 if (j & 0x01) quad4_x += 4;
502 if (j & 0x02) quad4_y += 4;
503
504 // set up the planes
505 y_plane = mpi->planes[0] + quad4_y * y_stride + quad4_x;
506 u_plane = mpi->planes[1] +
507 (quad4_y / 2) * u_stride + (quad4_x / 2);
508 v_plane = mpi->planes[2] +
509 (quad4_y / 2) * v_stride + (quad4_x / 2);
510
511 // decide how to handle this 4x4 quad
512 FETCH_NEXT_CODE();
513 switch(roq_code)
514 {
515 // 4x4 block is the same as in the previous frame;
516 // skip it
517 case 0:
518 break;
519
520 // 4x4 block is motion compensated from the previous frame
521 case 1:
522 CHECK_PREV_FRAME();
523 // prepare the pointers to the planes in the previous frame
524 FETCH_NEXT_ARGUMENT(); // argument contains motion vectors
525
526 // figure out the motion vectors
527 mx = quad4_x + 8 - (argument >> 4) - mean_motion_x;
528 my = quad4_y + 8 - (argument & 0x0F) - mean_motion_y;
529
530 prev_y_plane = info->prev_frame->planes[0] +
531 my * y_stride + mx;
532 prev_u_plane = info->prev_frame->planes[1] +
533 (my / 2) * u_stride + (mx + 1) / 2;
534 prev_v_plane = info->prev_frame->planes[2] +
535 (my / 2) * u_stride + (mx + 1) / 2;
536
537 // sanity check before rendering
538 copy_4x4_block(
539 y_plane,
540 u_plane,
541 v_plane,
542 prev_y_plane,
543 prev_u_plane,
544 prev_v_plane,
545 y_stride,
546 u_stride,
547 v_stride
548 );
549 break;
550
551 // 4x4 block is copied directly from v4 vector table
552 case 2:
553 FETCH_NEXT_ARGUMENT();
554 v4 = info->v4[argument];
555
556 paint_v4_block(
557 y_plane,
558 u_plane,
559 v_plane,
560 y_stride,
561 u_stride,
562 v_stride,
563 &info->v2[v4.v2_index[0]],
564 &info->v2[v4.v2_index[1]],
565 &info->v2[v4.v2_index[2]],
566 &info->v2[v4.v2_index[3]]);
567 break;
568
569 // 4x4 block is built from 4 2x2 vectors
570 case 3:
571 if (stream_ptr + 4 > encoded_size)
572 {
573 mp_msg(MSGT_DECVIDEO, MSGL_WARN,
574 "RoQ video: stream pointer just went out of bounds (2)\n");
575 return;
576 }
577 paint_v4_block(
578 y_plane,
579 u_plane,
580 v_plane,
581 y_stride,
582 u_stride,
583 v_stride,
584 &info->v2[encoded[stream_ptr + 0]],
585 &info->v2[encoded[stream_ptr + 1]],
586 &info->v2[encoded[stream_ptr + 2]],
587 &info->v2[encoded[stream_ptr + 3]]);
588 stream_ptr += 4;
589 break;
590 }
591 }
592 break;
593 }
594 }
595 }
596 }
597 }
598
599 // one last sanity check on the way out
600 // (apparently, it's not unusual to have 2 bytes left over after decode)
601 if (stream_ptr < encoded_size - 2)
602 {
603 mp_msg(MSGT_DECVIDEO, MSGL_WARN,
604 "RoQ video: completed frame decode with bytes left over (%d < %d)\n",
605 stream_ptr, encoded_size);
606 }
607
608 // save the current frame as the previous frame for the next iteration
609 info->prev_frame = mpi;
610 }
611
612 // Initialize the RoQ audio decoder, which is to say, initialize the table
613 // of squares.
614 void *roq_decode_audio_init(void)
615 {
616 short *square_array;
617 short square;
618 int i;
619
620 square_array = (short *)malloc(256 * sizeof(short));
621 if (!square_array)
622 return NULL;
623
624 for (i = 0; i < 128; i++)
625 {
626 square = i * i;
627 square_array[i] = square;
628 square_array[i + 128] = -square;
629 }
630
631 return square_array;
632 }
633
634 int roq_decode_audio(
635 unsigned short *output,
636 unsigned char *input,
637 int encoded_size,
638 int channels,
639 void *context)
640 {
641 short *square_array = (short *)context;
642 int i;
643 int predictor[2];
644 int channel_number = 0;
645
646 // prepare the initial predictors
647 if (channels == 1)
648 predictor[0] = LE_16(&input[0]);
649 else
650 {
651 predictor[0] = input[1] << 8;
652 predictor[1] = input[0] << 8;
653 }
654 SE_16BIT(predictor[0]);
655 SE_16BIT(predictor[1]);
656
657 // decode the samples
658 for (i = 2; i < encoded_size; i++)
659 {
660 predictor[channel_number] += square_array[input[i]];
661 CLAMP_S16(predictor[channel_number]);
662 output[i - 2] = predictor[channel_number];
663
664 // toggle channel
665 channel_number ^= channels - 1;
666 }
667
668 // return the number of samples decoded
669 return (encoded_size - 2);
670 }