Mercurial > libavcodec.hg
annotate smc.c @ 3198:6b9f0c4fbdbe libavcodec
First part of a series of speed-enchancing patches.
This one sets up a snow.h and makes snow use the dsputil function pointer
framework to access the three functions that will be implemented in asm
in the other parts of the patchset.
Patch by Robert Edele < yartrebo AH earthlink POIS net>
Original thread:
Subject: [Ffmpeg-devel] [PATCH] Snow mmx+sse2 asm optimizations
Date: Sun, 05 Feb 2006 12:47:14 -0500
author | gpoirier |
---|---|
date | Thu, 16 Mar 2006 19:18:18 +0000 |
parents | 0b546eab515d |
children | c8c591fe26f8 |
rev | line source |
---|---|
1610 | 1 /* |
2 * Quicktime Graphics (SMC) Video Decoder | |
3 * Copyright (C) 2003 the ffmpeg project | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
3036
0b546eab515d
Update licensing information: The FSF changed postal address.
diego
parents:
2979
diff
changeset
|
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
1610 | 18 * |
19 */ | |
20 | |
21 /** | |
22 * @file smc.c | |
23 * QT SMC Video Decoder by Mike Melanson (melanson@pcisys.net) | |
24 * For more information about the SMC format, visit: | |
25 * http://www.pcisys.net/~melanson/codecs/ | |
26 * | |
27 * The SMC decoder outputs PAL8 colorspace data. | |
28 */ | |
29 | |
30 #include <stdio.h> | |
31 #include <stdlib.h> | |
32 #include <string.h> | |
33 #include <unistd.h> | |
34 | |
35 #include "common.h" | |
36 #include "avcodec.h" | |
37 #include "dsputil.h" | |
38 | |
39 #define CPAIR 2 | |
40 #define CQUAD 4 | |
41 #define COCTET 8 | |
42 | |
43 #define COLORS_PER_TABLE 256 | |
44 | |
45 typedef struct SmcContext { | |
46 | |
47 AVCodecContext *avctx; | |
48 DSPContext dsp; | |
49 AVFrame frame; | |
50 | |
51 unsigned char *buf; | |
52 int size; | |
53 | |
54 /* SMC color tables */ | |
55 unsigned char color_pairs[COLORS_PER_TABLE * CPAIR]; | |
56 unsigned char color_quads[COLORS_PER_TABLE * CQUAD]; | |
57 unsigned char color_octets[COLORS_PER_TABLE * COCTET]; | |
58 | |
59 } SmcContext; | |
60 | |
61 #define GET_BLOCK_COUNT() \ | |
62 (opcode & 0x10) ? (1 + s->buf[stream_ptr++]) : 1 + (opcode & 0x0F); | |
63 | |
64 #define ADVANCE_BLOCK() \ | |
65 { \ | |
66 pixel_ptr += 4; \ | |
67 if (pixel_ptr >= width) \ | |
68 { \ | |
69 pixel_ptr = 0; \ | |
70 row_ptr += stride * 4; \ | |
71 } \ | |
72 total_blocks--; \ | |
73 if (total_blocks < 0) \ | |
74 { \ | |
1927 | 75 av_log(s->avctx, AV_LOG_INFO, "warning: block counter just went negative (this should not happen)\n"); \ |
1610 | 76 return; \ |
77 } \ | |
78 } | |
79 | |
80 static void smc_decode_stream(SmcContext *s) | |
81 { | |
82 int width = s->avctx->width; | |
83 int height = s->avctx->height; | |
84 int stride = s->frame.linesize[0]; | |
85 int i; | |
86 int stream_ptr = 0; | |
87 int chunk_size; | |
88 unsigned char opcode; | |
89 int n_blocks; | |
90 unsigned int color_flags; | |
91 unsigned int color_flags_a; | |
92 unsigned int color_flags_b; | |
93 unsigned int flag_mask; | |
94 | |
95 unsigned char *pixels = s->frame.data[0]; | |
96 | |
97 int image_size = height * s->frame.linesize[0]; | |
98 int row_ptr = 0; | |
99 int pixel_ptr = 0; | |
100 int pixel_x, pixel_y; | |
101 int row_inc = stride - 4; | |
102 int block_ptr; | |
103 int prev_block_ptr; | |
104 int prev_block_ptr1, prev_block_ptr2; | |
105 int prev_block_flag; | |
106 int total_blocks; | |
107 int color_table_index; /* indexes to color pair, quad, or octet tables */ | |
108 int pixel; | |
109 | |
110 int color_pair_index = 0; | |
111 int color_quad_index = 0; | |
112 int color_octet_index = 0; | |
113 | |
114 /* make the palette available */ | |
115 memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE); | |
116 if (s->avctx->palctrl->palette_changed) { | |
117 s->frame.palette_has_changed = 1; | |
118 s->avctx->palctrl->palette_changed = 0; | |
119 } | |
120 | |
121 chunk_size = BE_32(&s->buf[stream_ptr]) & 0x00FFFFFF; | |
122 stream_ptr += 4; | |
123 if (chunk_size != s->size) | |
1927 | 124 av_log(s->avctx, AV_LOG_INFO, "warning: MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n", |
1610 | 125 chunk_size, s->size); |
126 | |
127 chunk_size = s->size; | |
2103 | 128 total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4); |
1610 | 129 |
130 /* traverse through the blocks */ | |
131 while (total_blocks) { | |
132 /* sanity checks */ | |
133 /* make sure stream ptr hasn't gone out of bounds */ | |
134 if (stream_ptr > chunk_size) { | |
1927 | 135 av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)\n", |
1610 | 136 stream_ptr, chunk_size); |
137 return; | |
138 } | |
139 /* make sure the row pointer hasn't gone wild */ | |
140 if (row_ptr >= image_size) { | |
1927 | 141 av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (row ptr = %d, height = %d)\n", |
1610 | 142 row_ptr, image_size); |
143 return; | |
144 } | |
145 | |
146 opcode = s->buf[stream_ptr++]; | |
147 switch (opcode & 0xF0) { | |
148 /* skip n blocks */ | |
149 case 0x00: | |
150 case 0x10: | |
151 n_blocks = GET_BLOCK_COUNT(); | |
152 while (n_blocks--) { | |
153 ADVANCE_BLOCK(); | |
154 } | |
155 break; | |
156 | |
157 /* repeat last block n times */ | |
158 case 0x20: | |
159 case 0x30: | |
160 n_blocks = GET_BLOCK_COUNT(); | |
161 | |
162 /* sanity check */ | |
163 if ((row_ptr == 0) && (pixel_ptr == 0)) { | |
1927 | 164 av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but no blocks rendered yet\n", |
1610 | 165 opcode & 0xF0); |
166 break; | |
167 } | |
168 | |
169 /* figure out where the previous block started */ | |
170 if (pixel_ptr == 0) | |
2967 | 171 prev_block_ptr1 = |
1610 | 172 (row_ptr - s->avctx->width * 4) + s->avctx->width - 4; |
173 else | |
174 prev_block_ptr1 = row_ptr + pixel_ptr - 4; | |
175 | |
176 while (n_blocks--) { | |
177 block_ptr = row_ptr + pixel_ptr; | |
178 prev_block_ptr = prev_block_ptr1; | |
179 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
180 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
181 pixels[block_ptr++] = pixels[prev_block_ptr++]; | |
182 } | |
183 block_ptr += row_inc; | |
184 prev_block_ptr += row_inc; | |
185 } | |
186 ADVANCE_BLOCK(); | |
187 } | |
188 break; | |
189 | |
190 /* repeat previous pair of blocks n times */ | |
191 case 0x40: | |
192 case 0x50: | |
193 n_blocks = GET_BLOCK_COUNT(); | |
194 n_blocks *= 2; | |
195 | |
196 /* sanity check */ | |
197 if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) { | |
2979 | 198 av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n", |
1610 | 199 opcode & 0xF0); |
200 break; | |
201 } | |
202 | |
203 /* figure out where the previous 2 blocks started */ | |
204 if (pixel_ptr == 0) | |
2967 | 205 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + |
1610 | 206 s->avctx->width - 4 * 2; |
207 else if (pixel_ptr == 4) | |
208 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc; | |
209 else | |
210 prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2; | |
211 | |
212 if (pixel_ptr == 0) | |
213 prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc; | |
214 else | |
215 prev_block_ptr2 = row_ptr + pixel_ptr - 4; | |
216 | |
217 prev_block_flag = 0; | |
218 while (n_blocks--) { | |
219 block_ptr = row_ptr + pixel_ptr; | |
220 if (prev_block_flag) | |
221 prev_block_ptr = prev_block_ptr2; | |
222 else | |
223 prev_block_ptr = prev_block_ptr1; | |
224 prev_block_flag = !prev_block_flag; | |
225 | |
226 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
227 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
228 pixels[block_ptr++] = pixels[prev_block_ptr++]; | |
229 } | |
230 block_ptr += row_inc; | |
231 prev_block_ptr += row_inc; | |
232 } | |
233 ADVANCE_BLOCK(); | |
234 } | |
235 break; | |
236 | |
237 /* 1-color block encoding */ | |
238 case 0x60: | |
239 case 0x70: | |
240 n_blocks = GET_BLOCK_COUNT(); | |
241 pixel = s->buf[stream_ptr++]; | |
242 | |
243 while (n_blocks--) { | |
244 block_ptr = row_ptr + pixel_ptr; | |
245 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
246 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
247 pixels[block_ptr++] = pixel; | |
248 } | |
249 block_ptr += row_inc; | |
250 } | |
251 ADVANCE_BLOCK(); | |
252 } | |
253 break; | |
254 | |
255 /* 2-color block encoding */ | |
256 case 0x80: | |
257 case 0x90: | |
258 n_blocks = (opcode & 0x0F) + 1; | |
259 | |
260 /* figure out which color pair to use to paint the 2-color block */ | |
261 if ((opcode & 0xF0) == 0x80) { | |
262 /* fetch the next 2 colors from bytestream and store in next | |
263 * available entry in the color pair table */ | |
264 for (i = 0; i < CPAIR; i++) { | |
265 pixel = s->buf[stream_ptr++]; | |
266 color_table_index = CPAIR * color_pair_index + i; | |
267 s->color_pairs[color_table_index] = pixel; | |
268 } | |
269 /* this is the base index to use for this block */ | |
270 color_table_index = CPAIR * color_pair_index; | |
271 color_pair_index++; | |
272 /* wraparound */ | |
273 if (color_pair_index == COLORS_PER_TABLE) | |
274 color_pair_index = 0; | |
275 } else | |
276 color_table_index = CPAIR * s->buf[stream_ptr++]; | |
277 | |
278 while (n_blocks--) { | |
279 color_flags = BE_16(&s->buf[stream_ptr]); | |
280 stream_ptr += 2; | |
281 flag_mask = 0x8000; | |
282 block_ptr = row_ptr + pixel_ptr; | |
283 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
284 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
285 if (color_flags & flag_mask) | |
286 pixel = color_table_index + 1; | |
287 else | |
288 pixel = color_table_index; | |
289 flag_mask >>= 1; | |
290 pixels[block_ptr++] = s->color_pairs[pixel]; | |
291 } | |
292 block_ptr += row_inc; | |
293 } | |
294 ADVANCE_BLOCK(); | |
295 } | |
296 break; | |
297 | |
298 /* 4-color block encoding */ | |
299 case 0xA0: | |
300 case 0xB0: | |
301 n_blocks = (opcode & 0x0F) + 1; | |
302 | |
303 /* figure out which color quad to use to paint the 4-color block */ | |
304 if ((opcode & 0xF0) == 0xA0) { | |
305 /* fetch the next 4 colors from bytestream and store in next | |
306 * available entry in the color quad table */ | |
307 for (i = 0; i < CQUAD; i++) { | |
308 pixel = s->buf[stream_ptr++]; | |
309 color_table_index = CQUAD * color_quad_index + i; | |
310 s->color_quads[color_table_index] = pixel; | |
311 } | |
312 /* this is the base index to use for this block */ | |
313 color_table_index = CQUAD * color_quad_index; | |
314 color_quad_index++; | |
315 /* wraparound */ | |
316 if (color_quad_index == COLORS_PER_TABLE) | |
317 color_quad_index = 0; | |
318 } else | |
319 color_table_index = CQUAD * s->buf[stream_ptr++]; | |
320 | |
321 while (n_blocks--) { | |
322 color_flags = BE_32(&s->buf[stream_ptr]); | |
323 stream_ptr += 4; | |
324 /* flag mask actually acts as a bit shift count here */ | |
325 flag_mask = 30; | |
326 block_ptr = row_ptr + pixel_ptr; | |
327 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
328 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
2967 | 329 pixel = color_table_index + |
1610 | 330 ((color_flags >> flag_mask) & 0x03); |
331 flag_mask -= 2; | |
332 pixels[block_ptr++] = s->color_quads[pixel]; | |
333 } | |
334 block_ptr += row_inc; | |
335 } | |
336 ADVANCE_BLOCK(); | |
337 } | |
338 break; | |
339 | |
340 /* 8-color block encoding */ | |
341 case 0xC0: | |
342 case 0xD0: | |
343 n_blocks = (opcode & 0x0F) + 1; | |
344 | |
345 /* figure out which color octet to use to paint the 8-color block */ | |
346 if ((opcode & 0xF0) == 0xC0) { | |
347 /* fetch the next 8 colors from bytestream and store in next | |
348 * available entry in the color octet table */ | |
349 for (i = 0; i < COCTET; i++) { | |
350 pixel = s->buf[stream_ptr++]; | |
351 color_table_index = COCTET * color_octet_index + i; | |
352 s->color_octets[color_table_index] = pixel; | |
353 } | |
354 /* this is the base index to use for this block */ | |
355 color_table_index = COCTET * color_octet_index; | |
356 color_octet_index++; | |
357 /* wraparound */ | |
358 if (color_octet_index == COLORS_PER_TABLE) | |
359 color_octet_index = 0; | |
360 } else | |
361 color_table_index = COCTET * s->buf[stream_ptr++]; | |
362 | |
363 while (n_blocks--) { | |
364 /* | |
365 For this input of 6 hex bytes: | |
366 01 23 45 67 89 AB | |
367 Mangle it to this output: | |
368 flags_a = xx012456, flags_b = xx89A37B | |
369 */ | |
370 /* build the color flags */ | |
371 color_flags_a = color_flags_b = 0; | |
372 color_flags_a = | |
373 (s->buf[stream_ptr + 0] << 16) | | |
374 ((s->buf[stream_ptr + 1] & 0xF0) << 8) | | |
375 ((s->buf[stream_ptr + 2] & 0xF0) << 4) | | |
376 ((s->buf[stream_ptr + 2] & 0x0F) << 4) | | |
377 ((s->buf[stream_ptr + 3] & 0xF0) >> 4); | |
378 color_flags_b = | |
379 (s->buf[stream_ptr + 4] << 16) | | |
380 ((s->buf[stream_ptr + 5] & 0xF0) << 8) | | |
381 ((s->buf[stream_ptr + 1] & 0x0F) << 8) | | |
382 ((s->buf[stream_ptr + 3] & 0x0F) << 4) | | |
383 (s->buf[stream_ptr + 5] & 0x0F); | |
384 stream_ptr += 6; | |
385 | |
386 color_flags = color_flags_a; | |
387 /* flag mask actually acts as a bit shift count here */ | |
388 flag_mask = 21; | |
389 block_ptr = row_ptr + pixel_ptr; | |
390 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
391 /* reload flags at third row (iteration pixel_y == 2) */ | |
392 if (pixel_y == 2) { | |
393 color_flags = color_flags_b; | |
394 flag_mask = 21; | |
395 } | |
396 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
2967 | 397 pixel = color_table_index + |
1610 | 398 ((color_flags >> flag_mask) & 0x07); |
399 flag_mask -= 3; | |
400 pixels[block_ptr++] = s->color_octets[pixel]; | |
401 } | |
402 block_ptr += row_inc; | |
403 } | |
404 ADVANCE_BLOCK(); | |
405 } | |
406 break; | |
407 | |
408 /* 16-color block encoding (every pixel is a different color) */ | |
409 case 0xE0: | |
410 n_blocks = (opcode & 0x0F) + 1; | |
411 | |
412 while (n_blocks--) { | |
413 block_ptr = row_ptr + pixel_ptr; | |
414 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
415 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
416 pixels[block_ptr++] = s->buf[stream_ptr++]; | |
417 } | |
418 block_ptr += row_inc; | |
419 } | |
420 ADVANCE_BLOCK(); | |
421 } | |
422 break; | |
423 | |
424 case 0xF0: | |
1927 | 425 av_log(s->avctx, AV_LOG_INFO, "0xF0 opcode seen in SMC chunk (contact the developers)\n"); |
1610 | 426 break; |
427 } | |
428 } | |
429 } | |
430 | |
431 static int smc_decode_init(AVCodecContext *avctx) | |
432 { | |
433 SmcContext *s = (SmcContext *)avctx->priv_data; | |
434 | |
435 s->avctx = avctx; | |
436 avctx->pix_fmt = PIX_FMT_PAL8; | |
437 avctx->has_b_frames = 0; | |
438 dsputil_init(&s->dsp, avctx); | |
439 | |
1630 | 440 s->frame.data[0] = NULL; |
1610 | 441 |
442 return 0; | |
443 } | |
444 | |
445 static int smc_decode_frame(AVCodecContext *avctx, | |
446 void *data, int *data_size, | |
447 uint8_t *buf, int buf_size) | |
448 { | |
449 SmcContext *s = (SmcContext *)avctx->priv_data; | |
450 | |
451 s->buf = buf; | |
452 s->size = buf_size; | |
453 | |
454 s->frame.reference = 1; | |
2967 | 455 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | |
1769 | 456 FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE; |
1630 | 457 if (avctx->reget_buffer(avctx, &s->frame)) { |
1927 | 458 av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); |
1610 | 459 return -1; |
460 } | |
461 | |
462 smc_decode_stream(s); | |
463 | |
464 *data_size = sizeof(AVFrame); | |
465 *(AVFrame*)data = s->frame; | |
466 | |
467 /* always report that the buffer was completely consumed */ | |
468 return buf_size; | |
469 } | |
470 | |
471 static int smc_decode_end(AVCodecContext *avctx) | |
472 { | |
473 SmcContext *s = (SmcContext *)avctx->priv_data; | |
474 | |
1630 | 475 if (s->frame.data[0]) |
476 avctx->release_buffer(avctx, &s->frame); | |
1610 | 477 |
478 return 0; | |
479 } | |
480 | |
481 AVCodec smc_decoder = { | |
482 "smc", | |
483 CODEC_TYPE_VIDEO, | |
484 CODEC_ID_SMC, | |
485 sizeof(SmcContext), | |
486 smc_decode_init, | |
487 NULL, | |
488 smc_decode_end, | |
489 smc_decode_frame, | |
490 CODEC_CAP_DR1, | |
491 }; |