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