Mercurial > mplayer.hg
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) |