comparison roqav.c @ 4936:026329111b09

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