Mercurial > libavcodec.hg
annotate pngdec.c @ 5337:26f4095e35d2 libavcodec
separate en/decoder specific parts from png.c
author | mru |
---|---|
date | Sun, 15 Jul 2007 18:24:26 +0000 |
parents | png.c@e9a0c447dc73 |
children | a8c48a070cff |
rev | line source |
---|---|
2342 | 1 /* |
2 * PNG image format | |
3 * Copyright (c) 2003 Fabrice Bellard. | |
4 * | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3777
diff
changeset
|
5 * This file is part of FFmpeg. |
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3777
diff
changeset
|
6 * |
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3777
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or |
2342 | 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:
3777
diff
changeset
|
10 * version 2.1 of the License, or (at your option) any later version. |
2342 | 11 * |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3777
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
2342 | 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:
3777
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:
2967
diff
changeset
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
2342 | 20 */ |
21 #include "avcodec.h" | |
5067 | 22 #include "bytestream.h" |
5337 | 23 #include "png.h" |
2342 | 24 |
25 /* TODO: | |
26 * - add 2, 4 and 16 bit depth support | |
27 */ | |
28 | |
29 #include <zlib.h> | |
30 | |
31 //#define DEBUG | |
32 | |
33 /* Mask to determine which y pixels can be written in a pass */ | |
34 static const uint8_t png_pass_dsp_ymask[NB_PASSES] = { | |
35 0xff, 0xff, 0x0f, 0xcc, 0x33, 0xff, 0x55, | |
36 }; | |
37 | |
38 /* Mask to determine which pixels to overwrite while displaying */ | |
2967 | 39 static const uint8_t png_pass_dsp_mask[NB_PASSES] = { |
2342 | 40 0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff |
41 }; | |
42 | |
43 /* NOTE: we try to construct a good looking image at each pass. width | |
44 is the original image width. We also do pixel format convertion at | |
45 this stage */ | |
2967 | 46 static void png_put_interlaced_row(uint8_t *dst, int width, |
47 int bits_per_pixel, int pass, | |
2342 | 48 int color_type, const uint8_t *src) |
49 { | |
50 int x, mask, dsp_mask, j, src_x, b, bpp; | |
51 uint8_t *d; | |
52 const uint8_t *s; | |
2967 | 53 |
5337 | 54 mask = ff_png_pass_mask[pass]; |
2342 | 55 dsp_mask = png_pass_dsp_mask[pass]; |
56 switch(bits_per_pixel) { | |
57 case 1: | |
5097 | 58 /* we must initialize the line to zero before writing to it */ |
2342 | 59 if (pass == 0) |
60 memset(dst, 0, (width + 7) >> 3); | |
61 src_x = 0; | |
62 for(x = 0; x < width; x++) { | |
63 j = (x & 7); | |
64 if ((dsp_mask << j) & 0x80) { | |
65 b = (src[src_x >> 3] >> (7 - (src_x & 7))) & 1; | |
66 dst[x >> 3] |= b << (7 - j); | |
67 } | |
68 if ((mask << j) & 0x80) | |
69 src_x++; | |
70 } | |
71 break; | |
72 default: | |
73 bpp = bits_per_pixel >> 3; | |
74 d = dst; | |
75 s = src; | |
76 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { | |
77 for(x = 0; x < width; x++) { | |
78 j = x & 7; | |
79 if ((dsp_mask << j) & 0x80) { | |
80 *(uint32_t *)d = (s[3] << 24) | (s[0] << 16) | (s[1] << 8) | s[2]; | |
81 } | |
82 d += bpp; | |
83 if ((mask << j) & 0x80) | |
84 s += bpp; | |
85 } | |
86 } else { | |
87 for(x = 0; x < width; x++) { | |
88 j = x & 7; | |
89 if ((dsp_mask << j) & 0x80) { | |
90 memcpy(d, s, bpp); | |
91 } | |
92 d += bpp; | |
93 if ((mask << j) & 0x80) | |
94 s += bpp; | |
95 } | |
96 } | |
97 break; | |
98 } | |
99 } | |
100 | |
101 /* XXX: optimize */ | |
102 /* NOTE: 'dst' can be equal to 'last' */ | |
2967 | 103 static void png_filter_row(uint8_t *dst, int filter_type, |
2342 | 104 uint8_t *src, uint8_t *last, int size, int bpp) |
105 { | |
106 int i, p; | |
107 | |
108 switch(filter_type) { | |
109 case PNG_FILTER_VALUE_NONE: | |
110 memcpy(dst, src, size); | |
111 break; | |
112 case PNG_FILTER_VALUE_SUB: | |
113 for(i = 0; i < bpp; i++) { | |
114 dst[i] = src[i]; | |
115 } | |
116 for(i = bpp; i < size; i++) { | |
117 p = dst[i - bpp]; | |
118 dst[i] = p + src[i]; | |
119 } | |
120 break; | |
121 case PNG_FILTER_VALUE_UP: | |
122 for(i = 0; i < size; i++) { | |
123 p = last[i]; | |
124 dst[i] = p + src[i]; | |
125 } | |
126 break; | |
127 case PNG_FILTER_VALUE_AVG: | |
128 for(i = 0; i < bpp; i++) { | |
129 p = (last[i] >> 1); | |
130 dst[i] = p + src[i]; | |
131 } | |
132 for(i = bpp; i < size; i++) { | |
133 p = ((dst[i - bpp] + last[i]) >> 1); | |
134 dst[i] = p + src[i]; | |
135 } | |
136 break; | |
137 case PNG_FILTER_VALUE_PAETH: | |
138 for(i = 0; i < bpp; i++) { | |
139 p = last[i]; | |
140 dst[i] = p + src[i]; | |
141 } | |
142 for(i = bpp; i < size; i++) { | |
143 int a, b, c, pa, pb, pc; | |
144 | |
145 a = dst[i - bpp]; | |
146 b = last[i]; | |
147 c = last[i - bpp]; | |
148 | |
149 p = b - c; | |
150 pc = a - c; | |
151 | |
152 pa = abs(p); | |
153 pb = abs(pc); | |
154 pc = abs(p + pc); | |
155 | |
156 if (pa <= pb && pa <= pc) | |
157 p = a; | |
158 else if (pb <= pc) | |
159 p = b; | |
160 else | |
161 p = c; | |
162 dst[i] = p + src[i]; | |
163 } | |
164 break; | |
165 } | |
166 } | |
167 | |
4515 | 168 static void convert_to_rgb32(uint8_t *dst, const uint8_t *src, int width) |
2342 | 169 { |
170 int j; | |
171 unsigned int r, g, b, a; | |
172 | |
173 for(j = 0;j < width; j++) { | |
174 r = src[0]; | |
175 g = src[1]; | |
176 b = src[2]; | |
177 a = src[3]; | |
178 *(uint32_t *)dst = (a << 24) | (r << 16) | (g << 8) | b; | |
179 dst += 4; | |
180 src += 4; | |
181 } | |
182 } | |
183 | |
184 /* process exactly one decompressed row */ | |
185 static void png_handle_row(PNGContext *s) | |
186 { | |
187 uint8_t *ptr, *last_row; | |
188 int got_line; | |
2967 | 189 |
2342 | 190 if (!s->interlace_type) { |
191 ptr = s->image_buf + s->image_linesize * s->y; | |
192 /* need to swap bytes correctly for RGB_ALPHA */ | |
193 if (s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { | |
2967 | 194 png_filter_row(s->tmp_row, s->crow_buf[0], s->crow_buf + 1, |
2342 | 195 s->last_row, s->row_size, s->bpp); |
196 memcpy(s->last_row, s->tmp_row, s->row_size); | |
4515 | 197 convert_to_rgb32(ptr, s->tmp_row, s->width); |
2342 | 198 } else { |
199 /* in normal case, we avoid one copy */ | |
200 if (s->y == 0) | |
201 last_row = s->last_row; | |
202 else | |
203 last_row = ptr - s->image_linesize; | |
2967 | 204 |
205 png_filter_row(ptr, s->crow_buf[0], s->crow_buf + 1, | |
2342 | 206 last_row, s->row_size, s->bpp); |
207 } | |
208 s->y++; | |
209 if (s->y == s->height) { | |
210 s->state |= PNG_ALLIMAGE; | |
211 } | |
212 } else { | |
213 got_line = 0; | |
214 for(;;) { | |
215 ptr = s->image_buf + s->image_linesize * s->y; | |
5337 | 216 if ((ff_png_pass_ymask[s->pass] << (s->y & 7)) & 0x80) { |
2342 | 217 /* if we already read one row, it is time to stop to |
218 wait for the next one */ | |
219 if (got_line) | |
220 break; | |
2967 | 221 png_filter_row(s->tmp_row, s->crow_buf[0], s->crow_buf + 1, |
2342 | 222 s->last_row, s->pass_row_size, s->bpp); |
223 memcpy(s->last_row, s->tmp_row, s->pass_row_size); | |
224 got_line = 1; | |
225 } | |
226 if ((png_pass_dsp_ymask[s->pass] << (s->y & 7)) & 0x80) { | |
4515 | 227 /* NOTE: RGB32 is handled directly in png_put_interlaced_row */ |
2967 | 228 png_put_interlaced_row(ptr, s->width, s->bits_per_pixel, s->pass, |
2342 | 229 s->color_type, s->last_row); |
230 } | |
231 s->y++; | |
232 if (s->y == s->height) { | |
233 for(;;) { | |
234 if (s->pass == NB_PASSES - 1) { | |
235 s->state |= PNG_ALLIMAGE; | |
236 goto the_end; | |
237 } else { | |
238 s->pass++; | |
239 s->y = 0; | |
5337 | 240 s->pass_row_size = ff_png_pass_row_size(s->pass, |
2967 | 241 s->bits_per_pixel, |
2342 | 242 s->width); |
243 s->crow_size = s->pass_row_size + 1; | |
244 if (s->pass_row_size != 0) | |
245 break; | |
246 /* skip pass if empty row */ | |
247 } | |
248 } | |
249 } | |
250 } | |
251 the_end: ; | |
252 } | |
253 } | |
254 | |
255 static int png_decode_idat(PNGContext *s, int length) | |
256 { | |
257 int ret; | |
258 s->zstream.avail_in = length; | |
259 s->zstream.next_in = s->bytestream; | |
260 s->bytestream += length; | |
2967 | 261 |
2342 | 262 if(s->bytestream > s->bytestream_end) |
263 return -1; | |
264 | |
265 /* decode one line if possible */ | |
266 while (s->zstream.avail_in > 0) { | |
267 ret = inflate(&s->zstream, Z_PARTIAL_FLUSH); | |
268 if (ret != Z_OK && ret != Z_STREAM_END) { | |
269 return -1; | |
270 } | |
271 if (s->zstream.avail_out == 0) { | |
272 if (!(s->state & PNG_ALLIMAGE)) { | |
273 png_handle_row(s); | |
274 } | |
275 s->zstream.avail_out = s->crow_size; | |
276 s->zstream.next_out = s->crow_buf; | |
277 } | |
278 } | |
279 return 0; | |
280 } | |
281 | |
2967 | 282 static int decode_frame(AVCodecContext *avctx, |
2342 | 283 void *data, int *data_size, |
284 uint8_t *buf, int buf_size) | |
285 { | |
286 PNGContext * const s = avctx->priv_data; | |
287 AVFrame *picture = data; | |
288 AVFrame * const p= (AVFrame*)&s->picture; | |
289 uint32_t tag, length; | |
290 int ret, crc; | |
291 | |
292 s->bytestream_start= | |
293 s->bytestream= buf; | |
294 s->bytestream_end= buf + buf_size; | |
295 | |
296 /* check signature */ | |
5337 | 297 if (memcmp(s->bytestream, ff_pngsig, 8) != 0) |
2342 | 298 return -1; |
299 s->bytestream+= 8; | |
300 s->y= | |
301 s->state=0; | |
302 // memset(s, 0, sizeof(PNGContext)); | |
303 /* init the zlib */ | |
5337 | 304 s->zstream.zalloc = ff_png_zalloc; |
305 s->zstream.zfree = ff_png_zfree; | |
2342 | 306 s->zstream.opaque = NULL; |
307 ret = inflateInit(&s->zstream); | |
308 if (ret != Z_OK) | |
309 return -1; | |
310 for(;;) { | |
2347
c6280d48be02
When bswap_32 is a macro, png images fail to decode properly, patch by (Milan Cutka <cutka>at<szm>dot<sk>)
michael
parents:
2342
diff
changeset
|
311 int tag32; |
2342 | 312 if (s->bytestream >= s->bytestream_end) |
313 goto fail; | |
5067 | 314 length = bytestream_get_be32(&s->bytestream); |
2342 | 315 if (length > 0x7fffffff) |
316 goto fail; | |
5067 | 317 tag32 = bytestream_get_be32(&s->bytestream); |
2347
c6280d48be02
When bswap_32 is a macro, png images fail to decode properly, patch by (Milan Cutka <cutka>at<szm>dot<sk>)
michael
parents:
2342
diff
changeset
|
318 tag = bswap_32(tag32); |
2342 | 319 #ifdef DEBUG |
3177 | 320 av_log(avctx, AV_LOG_DEBUG, "png: tag=%c%c%c%c length=%u\n", |
2342 | 321 (tag & 0xff), |
322 ((tag >> 8) & 0xff), | |
323 ((tag >> 16) & 0xff), | |
324 ((tag >> 24) & 0xff), length); | |
325 #endif | |
326 switch(tag) { | |
327 case MKTAG('I', 'H', 'D', 'R'): | |
328 if (length != 13) | |
329 goto fail; | |
5067 | 330 s->width = bytestream_get_be32(&s->bytestream); |
331 s->height = bytestream_get_be32(&s->bytestream); | |
2422 | 332 if(avcodec_check_dimensions(avctx, s->width, s->height)){ |
333 s->width= s->height= 0; | |
334 goto fail; | |
335 } | |
2342 | 336 s->bit_depth = *s->bytestream++; |
337 s->color_type = *s->bytestream++; | |
338 s->compression_type = *s->bytestream++; | |
339 s->filter_type = *s->bytestream++; | |
340 s->interlace_type = *s->bytestream++; | |
5067 | 341 crc = bytestream_get_be32(&s->bytestream); |
2342 | 342 s->state |= PNG_IHDR; |
343 #ifdef DEBUG | |
3177 | 344 av_log(avctx, AV_LOG_DEBUG, "width=%d height=%d depth=%d color_type=%d compression_type=%d filter_type=%d interlace_type=%d\n", |
2967 | 345 s->width, s->height, s->bit_depth, s->color_type, |
2342 | 346 s->compression_type, s->filter_type, s->interlace_type); |
347 #endif | |
348 break; | |
349 case MKTAG('I', 'D', 'A', 'T'): | |
350 if (!(s->state & PNG_IHDR)) | |
351 goto fail; | |
352 if (!(s->state & PNG_IDAT)) { | |
353 /* init image info */ | |
354 avctx->width = s->width; | |
355 avctx->height = s->height; | |
356 | |
5337 | 357 s->channels = ff_png_get_nb_channels(s->color_type); |
2342 | 358 s->bits_per_pixel = s->bit_depth * s->channels; |
359 s->bpp = (s->bits_per_pixel + 7) >> 3; | |
360 s->row_size = (avctx->width * s->bits_per_pixel + 7) >> 3; | |
361 | |
2967 | 362 if (s->bit_depth == 8 && |
2342 | 363 s->color_type == PNG_COLOR_TYPE_RGB) { |
364 avctx->pix_fmt = PIX_FMT_RGB24; | |
2967 | 365 } else if (s->bit_depth == 8 && |
2342 | 366 s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { |
4494
ce643a22f049
Replace deprecated PIX_FMT names by the newer variants.
diego
parents:
4379
diff
changeset
|
367 avctx->pix_fmt = PIX_FMT_RGB32; |
2967 | 368 } else if (s->bit_depth == 8 && |
2342 | 369 s->color_type == PNG_COLOR_TYPE_GRAY) { |
370 avctx->pix_fmt = PIX_FMT_GRAY8; | |
4067 | 371 } else if (s->bit_depth == 16 && |
372 s->color_type == PNG_COLOR_TYPE_GRAY) { | |
373 avctx->pix_fmt = PIX_FMT_GRAY16BE; | |
2967 | 374 } else if (s->bit_depth == 1 && |
2342 | 375 s->color_type == PNG_COLOR_TYPE_GRAY) { |
376 avctx->pix_fmt = PIX_FMT_MONOBLACK; | |
377 } else if (s->color_type == PNG_COLOR_TYPE_PALETTE) { | |
378 avctx->pix_fmt = PIX_FMT_PAL8; | |
379 } else { | |
380 goto fail; | |
381 } | |
382 if(p->data[0]) | |
383 avctx->release_buffer(avctx, p); | |
2967 | 384 |
2342 | 385 p->reference= 0; |
386 if(avctx->get_buffer(avctx, p) < 0){ | |
387 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |
388 goto fail; | |
389 } | |
390 p->pict_type= FF_I_TYPE; | |
391 p->key_frame= 1; | |
392 p->interlaced_frame = !!s->interlace_type; | |
393 | |
394 /* compute the compressed row size */ | |
395 if (!s->interlace_type) { | |
396 s->crow_size = s->row_size + 1; | |
397 } else { | |
398 s->pass = 0; | |
5337 | 399 s->pass_row_size = ff_png_pass_row_size(s->pass, |
2967 | 400 s->bits_per_pixel, |
2342 | 401 s->width); |
402 s->crow_size = s->pass_row_size + 1; | |
403 } | |
404 #ifdef DEBUG | |
3177 | 405 av_log(avctx, AV_LOG_DEBUG, "row_size=%d crow_size =%d\n", |
2342 | 406 s->row_size, s->crow_size); |
407 #endif | |
408 s->image_buf = p->data[0]; | |
409 s->image_linesize = p->linesize[0]; | |
410 /* copy the palette if needed */ | |
411 if (s->color_type == PNG_COLOR_TYPE_PALETTE) | |
412 memcpy(p->data[1], s->palette, 256 * sizeof(uint32_t)); | |
413 /* empty row is used if differencing to the first row */ | |
414 s->last_row = av_mallocz(s->row_size); | |
415 if (!s->last_row) | |
416 goto fail; | |
417 if (s->interlace_type || | |
418 s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { | |
419 s->tmp_row = av_malloc(s->row_size); | |
420 if (!s->tmp_row) | |
421 goto fail; | |
422 } | |
423 /* compressed row */ | |
424 s->crow_buf = av_malloc(s->row_size + 1); | |
425 if (!s->crow_buf) | |
426 goto fail; | |
427 s->zstream.avail_out = s->crow_size; | |
428 s->zstream.next_out = s->crow_buf; | |
429 } | |
430 s->state |= PNG_IDAT; | |
431 if (png_decode_idat(s, length) < 0) | |
432 goto fail; | |
433 /* skip crc */ | |
5067 | 434 crc = bytestream_get_be32(&s->bytestream); |
2342 | 435 break; |
436 case MKTAG('P', 'L', 'T', 'E'): | |
437 { | |
438 int n, i, r, g, b; | |
2967 | 439 |
2342 | 440 if ((length % 3) != 0 || length > 256 * 3) |
441 goto skip_tag; | |
442 /* read the palette */ | |
443 n = length / 3; | |
444 for(i=0;i<n;i++) { | |
445 r = *s->bytestream++; | |
446 g = *s->bytestream++; | |
447 b = *s->bytestream++; | |
448 s->palette[i] = (0xff << 24) | (r << 16) | (g << 8) | b; | |
449 } | |
450 for(;i<256;i++) { | |
451 s->palette[i] = (0xff << 24); | |
452 } | |
453 s->state |= PNG_PLTE; | |
5067 | 454 crc = bytestream_get_be32(&s->bytestream); |
2342 | 455 } |
456 break; | |
457 case MKTAG('t', 'R', 'N', 'S'): | |
458 { | |
459 int v, i; | |
460 | |
461 /* read the transparency. XXX: Only palette mode supported */ | |
462 if (s->color_type != PNG_COLOR_TYPE_PALETTE || | |
463 length > 256 || | |
464 !(s->state & PNG_PLTE)) | |
465 goto skip_tag; | |
466 for(i=0;i<length;i++) { | |
467 v = *s->bytestream++; | |
468 s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24); | |
469 } | |
5067 | 470 crc = bytestream_get_be32(&s->bytestream); |
2342 | 471 } |
472 break; | |
473 case MKTAG('I', 'E', 'N', 'D'): | |
474 if (!(s->state & PNG_ALLIMAGE)) | |
475 goto fail; | |
5067 | 476 crc = bytestream_get_be32(&s->bytestream); |
2342 | 477 goto exit_loop; |
478 default: | |
479 /* skip tag */ | |
480 skip_tag: | |
481 s->bytestream += length + 4; | |
482 break; | |
483 } | |
484 } | |
485 exit_loop: | |
486 *picture= *(AVFrame*)&s->picture; | |
487 *data_size = sizeof(AVPicture); | |
488 | |
489 ret = s->bytestream - s->bytestream_start; | |
490 the_end: | |
491 inflateEnd(&s->zstream); | |
492 av_freep(&s->crow_buf); | |
493 av_freep(&s->last_row); | |
494 av_freep(&s->tmp_row); | |
495 return ret; | |
496 fail: | |
497 ret = -1; | |
498 goto the_end; | |
499 } | |
500 | |
501 AVCodec png_decoder = { | |
502 "png", | |
503 CODEC_TYPE_VIDEO, | |
504 CODEC_ID_PNG, | |
505 sizeof(PNGContext), | |
5337 | 506 ff_png_common_init, |
2342 | 507 NULL, |
508 NULL, //decode_end, | |
509 decode_frame, | |
510 0 /*CODEC_CAP_DR1*/ /*| CODEC_CAP_DRAW_HORIZ_BAND*/, | |
511 NULL | |
512 }; |