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