Mercurial > libavcodec.hg
annotate smc.c @ 9950:a23ecc9d7976 libavcodec
Make VAAPI/VDPAU variant of decoder foo depend on decoder foo.
The VAAPI/VDPAU variants of foo require almost all of the code of foo.
Thus it makes little sense to enable just the accelerated variant.
This allows refactoring some object dependencies in the Makefiles.
author | diego |
---|---|
date | Sun, 12 Jul 2009 13:22:01 +0000 |
parents | 54bc8a2727b0 |
children | 5da84f0d0a55 |
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 /** | |
8718
e9d9d946f213
Use full internal pathname in doxygen @file directives.
diego
parents:
8573
diff
changeset
|
23 * @file libavcodec/smc.c |
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 #include <unistd.h> | |
35 | |
8573
2acf0ae7b041
Fix build: Add intreadwrite.h and bswap.h #includes where necessary.
diego
parents:
7040
diff
changeset
|
36 #include "libavutil/intreadwrite.h" |
1610 | 37 #include "avcodec.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 AVFrame frame; | |
49 | |
6252 | 50 const unsigned char *buf; |
1610 | 51 int size; |
52 | |
53 /* SMC color tables */ | |
54 unsigned char color_pairs[COLORS_PER_TABLE * CPAIR]; | |
55 unsigned char color_quads[COLORS_PER_TABLE * CQUAD]; | |
56 unsigned char color_octets[COLORS_PER_TABLE * COCTET]; | |
57 | |
58 } SmcContext; | |
59 | |
60 #define GET_BLOCK_COUNT() \ | |
61 (opcode & 0x10) ? (1 + s->buf[stream_ptr++]) : 1 + (opcode & 0x0F); | |
62 | |
63 #define ADVANCE_BLOCK() \ | |
64 { \ | |
65 pixel_ptr += 4; \ | |
66 if (pixel_ptr >= width) \ | |
67 { \ | |
68 pixel_ptr = 0; \ | |
69 row_ptr += stride * 4; \ | |
70 } \ | |
71 total_blocks--; \ | |
72 if (total_blocks < 0) \ | |
73 { \ | |
1927 | 74 av_log(s->avctx, AV_LOG_INFO, "warning: block counter just went negative (this should not happen)\n"); \ |
1610 | 75 return; \ |
76 } \ | |
77 } | |
78 | |
79 static void smc_decode_stream(SmcContext *s) | |
80 { | |
81 int width = s->avctx->width; | |
82 int height = s->avctx->height; | |
83 int stride = s->frame.linesize[0]; | |
84 int i; | |
85 int stream_ptr = 0; | |
86 int chunk_size; | |
87 unsigned char opcode; | |
88 int n_blocks; | |
89 unsigned int color_flags; | |
90 unsigned int color_flags_a; | |
91 unsigned int color_flags_b; | |
92 unsigned int flag_mask; | |
93 | |
94 unsigned char *pixels = s->frame.data[0]; | |
95 | |
96 int image_size = height * s->frame.linesize[0]; | |
97 int row_ptr = 0; | |
98 int pixel_ptr = 0; | |
99 int pixel_x, pixel_y; | |
100 int row_inc = stride - 4; | |
101 int block_ptr; | |
102 int prev_block_ptr; | |
103 int prev_block_ptr1, prev_block_ptr2; | |
104 int prev_block_flag; | |
105 int total_blocks; | |
106 int color_table_index; /* indexes to color pair, quad, or octet tables */ | |
107 int pixel; | |
108 | |
109 int color_pair_index = 0; | |
110 int color_quad_index = 0; | |
111 int color_octet_index = 0; | |
112 | |
113 /* make the palette available */ | |
114 memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE); | |
115 if (s->avctx->palctrl->palette_changed) { | |
116 s->frame.palette_has_changed = 1; | |
117 s->avctx->palctrl->palette_changed = 0; | |
118 } | |
119 | |
4364 | 120 chunk_size = AV_RB32(&s->buf[stream_ptr]) & 0x00FFFFFF; |
1610 | 121 stream_ptr += 4; |
122 if (chunk_size != s->size) | |
1927 | 123 av_log(s->avctx, AV_LOG_INFO, "warning: MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n", |
1610 | 124 chunk_size, s->size); |
125 | |
126 chunk_size = s->size; | |
2103 | 127 total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4); |
1610 | 128 |
129 /* traverse through the blocks */ | |
130 while (total_blocks) { | |
131 /* sanity checks */ | |
132 /* make sure stream ptr hasn't gone out of bounds */ | |
133 if (stream_ptr > chunk_size) { | |
1927 | 134 av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)\n", |
1610 | 135 stream_ptr, chunk_size); |
136 return; | |
137 } | |
138 /* make sure the row pointer hasn't gone wild */ | |
139 if (row_ptr >= image_size) { | |
1927 | 140 av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (row ptr = %d, height = %d)\n", |
1610 | 141 row_ptr, image_size); |
142 return; | |
143 } | |
144 | |
145 opcode = s->buf[stream_ptr++]; | |
146 switch (opcode & 0xF0) { | |
147 /* skip n blocks */ | |
148 case 0x00: | |
149 case 0x10: | |
150 n_blocks = GET_BLOCK_COUNT(); | |
151 while (n_blocks--) { | |
152 ADVANCE_BLOCK(); | |
153 } | |
154 break; | |
155 | |
156 /* repeat last block n times */ | |
157 case 0x20: | |
158 case 0x30: | |
159 n_blocks = GET_BLOCK_COUNT(); | |
160 | |
161 /* sanity check */ | |
162 if ((row_ptr == 0) && (pixel_ptr == 0)) { | |
1927 | 163 av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but no blocks rendered yet\n", |
1610 | 164 opcode & 0xF0); |
165 break; | |
166 } | |
167 | |
168 /* figure out where the previous block started */ | |
169 if (pixel_ptr == 0) | |
2967 | 170 prev_block_ptr1 = |
1610 | 171 (row_ptr - s->avctx->width * 4) + s->avctx->width - 4; |
172 else | |
173 prev_block_ptr1 = row_ptr + pixel_ptr - 4; | |
174 | |
175 while (n_blocks--) { | |
176 block_ptr = row_ptr + pixel_ptr; | |
177 prev_block_ptr = prev_block_ptr1; | |
178 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
179 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
180 pixels[block_ptr++] = pixels[prev_block_ptr++]; | |
181 } | |
182 block_ptr += row_inc; | |
183 prev_block_ptr += row_inc; | |
184 } | |
185 ADVANCE_BLOCK(); | |
186 } | |
187 break; | |
188 | |
189 /* repeat previous pair of blocks n times */ | |
190 case 0x40: | |
191 case 0x50: | |
192 n_blocks = GET_BLOCK_COUNT(); | |
193 n_blocks *= 2; | |
194 | |
195 /* sanity check */ | |
196 if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) { | |
2979 | 197 av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n", |
1610 | 198 opcode & 0xF0); |
199 break; | |
200 } | |
201 | |
202 /* figure out where the previous 2 blocks started */ | |
203 if (pixel_ptr == 0) | |
2967 | 204 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + |
1610 | 205 s->avctx->width - 4 * 2; |
206 else if (pixel_ptr == 4) | |
207 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc; | |
208 else | |
209 prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2; | |
210 | |
211 if (pixel_ptr == 0) | |
212 prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc; | |
213 else | |
214 prev_block_ptr2 = row_ptr + pixel_ptr - 4; | |
215 | |
216 prev_block_flag = 0; | |
217 while (n_blocks--) { | |
218 block_ptr = row_ptr + pixel_ptr; | |
219 if (prev_block_flag) | |
220 prev_block_ptr = prev_block_ptr2; | |
221 else | |
222 prev_block_ptr = prev_block_ptr1; | |
223 prev_block_flag = !prev_block_flag; | |
224 | |
225 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
226 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
227 pixels[block_ptr++] = pixels[prev_block_ptr++]; | |
228 } | |
229 block_ptr += row_inc; | |
230 prev_block_ptr += row_inc; | |
231 } | |
232 ADVANCE_BLOCK(); | |
233 } | |
234 break; | |
235 | |
236 /* 1-color block encoding */ | |
237 case 0x60: | |
238 case 0x70: | |
239 n_blocks = GET_BLOCK_COUNT(); | |
240 pixel = s->buf[stream_ptr++]; | |
241 | |
242 while (n_blocks--) { | |
243 block_ptr = row_ptr + pixel_ptr; | |
244 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
245 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
246 pixels[block_ptr++] = pixel; | |
247 } | |
248 block_ptr += row_inc; | |
249 } | |
250 ADVANCE_BLOCK(); | |
251 } | |
252 break; | |
253 | |
254 /* 2-color block encoding */ | |
255 case 0x80: | |
256 case 0x90: | |
257 n_blocks = (opcode & 0x0F) + 1; | |
258 | |
259 /* figure out which color pair to use to paint the 2-color block */ | |
260 if ((opcode & 0xF0) == 0x80) { | |
261 /* fetch the next 2 colors from bytestream and store in next | |
262 * available entry in the color pair table */ | |
263 for (i = 0; i < CPAIR; i++) { | |
264 pixel = s->buf[stream_ptr++]; | |
265 color_table_index = CPAIR * color_pair_index + i; | |
266 s->color_pairs[color_table_index] = pixel; | |
267 } | |
268 /* this is the base index to use for this block */ | |
269 color_table_index = CPAIR * color_pair_index; | |
270 color_pair_index++; | |
271 /* wraparound */ | |
272 if (color_pair_index == COLORS_PER_TABLE) | |
273 color_pair_index = 0; | |
274 } else | |
275 color_table_index = CPAIR * s->buf[stream_ptr++]; | |
276 | |
277 while (n_blocks--) { | |
4364 | 278 color_flags = AV_RB16(&s->buf[stream_ptr]); |
1610 | 279 stream_ptr += 2; |
280 flag_mask = 0x8000; | |
281 block_ptr = row_ptr + pixel_ptr; | |
282 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
283 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
284 if (color_flags & flag_mask) | |
285 pixel = color_table_index + 1; | |
286 else | |
287 pixel = color_table_index; | |
288 flag_mask >>= 1; | |
289 pixels[block_ptr++] = s->color_pairs[pixel]; | |
290 } | |
291 block_ptr += row_inc; | |
292 } | |
293 ADVANCE_BLOCK(); | |
294 } | |
295 break; | |
296 | |
297 /* 4-color block encoding */ | |
298 case 0xA0: | |
299 case 0xB0: | |
300 n_blocks = (opcode & 0x0F) + 1; | |
301 | |
302 /* figure out which color quad to use to paint the 4-color block */ | |
303 if ((opcode & 0xF0) == 0xA0) { | |
304 /* fetch the next 4 colors from bytestream and store in next | |
305 * available entry in the color quad table */ | |
306 for (i = 0; i < CQUAD; i++) { | |
307 pixel = s->buf[stream_ptr++]; | |
308 color_table_index = CQUAD * color_quad_index + i; | |
309 s->color_quads[color_table_index] = pixel; | |
310 } | |
311 /* this is the base index to use for this block */ | |
312 color_table_index = CQUAD * color_quad_index; | |
313 color_quad_index++; | |
314 /* wraparound */ | |
315 if (color_quad_index == COLORS_PER_TABLE) | |
316 color_quad_index = 0; | |
317 } else | |
318 color_table_index = CQUAD * s->buf[stream_ptr++]; | |
319 | |
320 while (n_blocks--) { | |
4364 | 321 color_flags = AV_RB32(&s->buf[stream_ptr]); |
1610 | 322 stream_ptr += 4; |
323 /* flag mask actually acts as a bit shift count here */ | |
324 flag_mask = 30; | |
325 block_ptr = row_ptr + pixel_ptr; | |
326 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
327 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
2967 | 328 pixel = color_table_index + |
1610 | 329 ((color_flags >> flag_mask) & 0x03); |
330 flag_mask -= 2; | |
331 pixels[block_ptr++] = s->color_quads[pixel]; | |
332 } | |
333 block_ptr += row_inc; | |
334 } | |
335 ADVANCE_BLOCK(); | |
336 } | |
337 break; | |
338 | |
339 /* 8-color block encoding */ | |
340 case 0xC0: | |
341 case 0xD0: | |
342 n_blocks = (opcode & 0x0F) + 1; | |
343 | |
344 /* figure out which color octet to use to paint the 8-color block */ | |
345 if ((opcode & 0xF0) == 0xC0) { | |
346 /* fetch the next 8 colors from bytestream and store in next | |
347 * available entry in the color octet table */ | |
348 for (i = 0; i < COCTET; i++) { | |
349 pixel = s->buf[stream_ptr++]; | |
350 color_table_index = COCTET * color_octet_index + i; | |
351 s->color_octets[color_table_index] = pixel; | |
352 } | |
353 /* this is the base index to use for this block */ | |
354 color_table_index = COCTET * color_octet_index; | |
355 color_octet_index++; | |
356 /* wraparound */ | |
357 if (color_octet_index == COLORS_PER_TABLE) | |
358 color_octet_index = 0; | |
359 } else | |
360 color_table_index = COCTET * s->buf[stream_ptr++]; | |
361 | |
362 while (n_blocks--) { | |
363 /* | |
364 For this input of 6 hex bytes: | |
365 01 23 45 67 89 AB | |
366 Mangle it to this output: | |
367 flags_a = xx012456, flags_b = xx89A37B | |
368 */ | |
369 /* build the color flags */ | |
370 color_flags_a = color_flags_b = 0; | |
371 color_flags_a = | |
372 (s->buf[stream_ptr + 0] << 16) | | |
373 ((s->buf[stream_ptr + 1] & 0xF0) << 8) | | |
374 ((s->buf[stream_ptr + 2] & 0xF0) << 4) | | |
375 ((s->buf[stream_ptr + 2] & 0x0F) << 4) | | |
376 ((s->buf[stream_ptr + 3] & 0xF0) >> 4); | |
377 color_flags_b = | |
378 (s->buf[stream_ptr + 4] << 16) | | |
379 ((s->buf[stream_ptr + 5] & 0xF0) << 8) | | |
380 ((s->buf[stream_ptr + 1] & 0x0F) << 8) | | |
381 ((s->buf[stream_ptr + 3] & 0x0F) << 4) | | |
382 (s->buf[stream_ptr + 5] & 0x0F); | |
383 stream_ptr += 6; | |
384 | |
385 color_flags = color_flags_a; | |
386 /* flag mask actually acts as a bit shift count here */ | |
387 flag_mask = 21; | |
388 block_ptr = row_ptr + pixel_ptr; | |
389 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
390 /* reload flags at third row (iteration pixel_y == 2) */ | |
391 if (pixel_y == 2) { | |
392 color_flags = color_flags_b; | |
393 flag_mask = 21; | |
394 } | |
395 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
2967 | 396 pixel = color_table_index + |
1610 | 397 ((color_flags >> flag_mask) & 0x07); |
398 flag_mask -= 3; | |
399 pixels[block_ptr++] = s->color_octets[pixel]; | |
400 } | |
401 block_ptr += row_inc; | |
402 } | |
403 ADVANCE_BLOCK(); | |
404 } | |
405 break; | |
406 | |
407 /* 16-color block encoding (every pixel is a different color) */ | |
408 case 0xE0: | |
409 n_blocks = (opcode & 0x0F) + 1; | |
410 | |
411 while (n_blocks--) { | |
412 block_ptr = row_ptr + pixel_ptr; | |
413 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
414 for (pixel_x = 0; pixel_x < 4; pixel_x++) { | |
415 pixels[block_ptr++] = s->buf[stream_ptr++]; | |
416 } | |
417 block_ptr += row_inc; | |
418 } | |
419 ADVANCE_BLOCK(); | |
420 } | |
421 break; | |
422 | |
423 case 0xF0: | |
1927 | 424 av_log(s->avctx, AV_LOG_INFO, "0xF0 opcode seen in SMC chunk (contact the developers)\n"); |
1610 | 425 break; |
426 } | |
427 } | |
428 } | |
429 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6484
diff
changeset
|
430 static av_cold int smc_decode_init(AVCodecContext *avctx) |
1610 | 431 { |
4827 | 432 SmcContext *s = avctx->priv_data; |
1610 | 433 |
434 s->avctx = avctx; | |
435 avctx->pix_fmt = PIX_FMT_PAL8; | |
436 | |
1630 | 437 s->frame.data[0] = NULL; |
1610 | 438 |
439 return 0; | |
440 } | |
441 | |
442 static int smc_decode_frame(AVCodecContext *avctx, | |
443 void *data, int *data_size, | |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8718
diff
changeset
|
444 AVPacket *avpkt) |
1610 | 445 { |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8718
diff
changeset
|
446 const uint8_t *buf = avpkt->data; |
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8718
diff
changeset
|
447 int buf_size = avpkt->size; |
4827 | 448 SmcContext *s = avctx->priv_data; |
1610 | 449 |
450 s->buf = buf; | |
451 s->size = buf_size; | |
452 | |
453 s->frame.reference = 1; | |
2967 | 454 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | |
1769 | 455 FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE; |
1630 | 456 if (avctx->reget_buffer(avctx, &s->frame)) { |
1927 | 457 av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); |
1610 | 458 return -1; |
459 } | |
460 | |
461 smc_decode_stream(s); | |
462 | |
463 *data_size = sizeof(AVFrame); | |
464 *(AVFrame*)data = s->frame; | |
465 | |
466 /* always report that the buffer was completely consumed */ | |
467 return buf_size; | |
468 } | |
469 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6484
diff
changeset
|
470 static av_cold int smc_decode_end(AVCodecContext *avctx) |
1610 | 471 { |
4827 | 472 SmcContext *s = avctx->priv_data; |
1610 | 473 |
1630 | 474 if (s->frame.data[0]) |
475 avctx->release_buffer(avctx, &s->frame); | |
1610 | 476 |
477 return 0; | |
478 } | |
479 | |
480 AVCodec smc_decoder = { | |
481 "smc", | |
482 CODEC_TYPE_VIDEO, | |
483 CODEC_ID_SMC, | |
484 sizeof(SmcContext), | |
485 smc_decode_init, | |
486 NULL, | |
487 smc_decode_end, | |
488 smc_decode_frame, | |
489 CODEC_CAP_DR1, | |
7040
e943e1409077
Make AVCodec long_names definition conditional depending on CONFIG_SMALL.
stefano
parents:
6712
diff
changeset
|
490 .long_name = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"), |
1610 | 491 }; |