Mercurial > libavcodec.hg
annotate png.c @ 2497:69adfbbdcdeb libavcodec
- samples from mplayer ftp in the "adv" profile seem to have profile=2,
which isn't the advanced one; and indeed, using adv. profile parser fails.
Using normal parser works, and that's what is done
- attempt at taking care of stride for NORM2 bitplane decoding
- duplication of much code from msmpeg4.c; this code isn't yet used, but
goes down as far as the block layer (mainly Transform Type stuff, the
remains are wild editing without checking). Unusable yet, and lacks the AC
decoding (but a step further in bitstream parsing)
patch by anonymous
author | michael |
---|---|
date | Fri, 04 Feb 2005 02:20:38 +0000 |
parents | f67b63ed036d |
children | b2846918585c |
rev | line source |
---|---|
2342 | 1 /* |
2 * PNG image format | |
3 * Copyright (c) 2003 Fabrice Bellard. | |
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 | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 #include "avcodec.h" | |
20 | |
21 /* TODO: | |
22 * - add 2, 4 and 16 bit depth support | |
23 * - use filters when generating a png (better compression) | |
24 */ | |
25 | |
26 #ifdef CONFIG_ZLIB | |
27 #include <zlib.h> | |
28 | |
29 //#define DEBUG | |
30 | |
31 #define PNG_COLOR_MASK_PALETTE 1 | |
32 #define PNG_COLOR_MASK_COLOR 2 | |
33 #define PNG_COLOR_MASK_ALPHA 4 | |
34 | |
35 #define PNG_COLOR_TYPE_GRAY 0 | |
36 #define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) | |
37 #define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) | |
38 #define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) | |
39 #define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) | |
40 | |
41 #define PNG_FILTER_VALUE_NONE 0 | |
42 #define PNG_FILTER_VALUE_SUB 1 | |
43 #define PNG_FILTER_VALUE_UP 2 | |
44 #define PNG_FILTER_VALUE_AVG 3 | |
45 #define PNG_FILTER_VALUE_PAETH 4 | |
46 | |
47 #define PNG_IHDR 0x0001 | |
48 #define PNG_IDAT 0x0002 | |
49 #define PNG_ALLIMAGE 0x0004 | |
50 #define PNG_PLTE 0x0008 | |
51 | |
52 #define NB_PASSES 7 | |
53 | |
54 #define IOBUF_SIZE 4096 | |
55 | |
56 typedef struct PNGContext { | |
57 uint8_t *bytestream; | |
58 uint8_t *bytestream_start; | |
59 uint8_t *bytestream_end; | |
60 AVFrame picture; | |
61 | |
62 int state; | |
63 int width, height; | |
64 int bit_depth; | |
65 int color_type; | |
66 int compression_type; | |
67 int interlace_type; | |
68 int filter_type; | |
69 int channels; | |
70 int bits_per_pixel; | |
71 int bpp; | |
72 | |
73 uint8_t *image_buf; | |
74 int image_linesize; | |
75 uint32_t palette[256]; | |
76 uint8_t *crow_buf; | |
77 uint8_t *last_row; | |
78 uint8_t *tmp_row; | |
79 int pass; | |
80 int crow_size; /* compressed row size (include filter type) */ | |
81 int row_size; /* decompressed row size */ | |
82 int pass_row_size; /* decompress row size of the current pass */ | |
83 int y; | |
84 z_stream zstream; | |
85 uint8_t buf[IOBUF_SIZE]; | |
86 } PNGContext; | |
87 | |
88 static unsigned int get32(uint8_t **b){ | |
89 (*b) += 4; | |
90 return ((*b)[-4]<<24) + ((*b)[-3]<<16) + ((*b)[-2]<<8) + (*b)[-1]; | |
91 } | |
92 | |
93 static void put32(uint8_t **b, unsigned int v){ | |
94 *(*b)++= v>>24; | |
95 *(*b)++= v>>16; | |
96 *(*b)++= v>>8; | |
97 *(*b)++= v; | |
98 } | |
99 | |
100 static const uint8_t pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; | |
101 | |
102 /* Mask to determine which y pixels are valid in a pass */ | |
103 static const uint8_t png_pass_ymask[NB_PASSES] = { | |
104 0x80, 0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, | |
105 }; | |
106 | |
107 /* Mask to determine which y pixels can be written in a pass */ | |
108 static const uint8_t png_pass_dsp_ymask[NB_PASSES] = { | |
109 0xff, 0xff, 0x0f, 0xcc, 0x33, 0xff, 0x55, | |
110 }; | |
111 | |
112 /* minimum x value */ | |
113 static const uint8_t png_pass_xmin[NB_PASSES] = { | |
114 0, 4, 0, 2, 0, 1, 0 | |
115 }; | |
116 | |
117 /* x shift to get row width */ | |
118 static const uint8_t png_pass_xshift[NB_PASSES] = { | |
119 3, 3, 2, 2, 1, 1, 0 | |
120 }; | |
121 | |
122 /* Mask to determine which pixels are valid in a pass */ | |
123 static const uint8_t png_pass_mask[NB_PASSES] = { | |
124 0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff | |
125 }; | |
126 | |
127 /* Mask to determine which pixels to overwrite while displaying */ | |
128 static const uint8_t png_pass_dsp_mask[NB_PASSES] = { | |
129 0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff | |
130 }; | |
131 #if 0 | |
132 static int png_probe(AVProbeData *pd) | |
133 { | |
134 if (pd->buf_size >= 8 && | |
135 memcmp(pd->buf, pngsig, 8) == 0) | |
136 return AVPROBE_SCORE_MAX; | |
137 else | |
138 return 0; | |
139 } | |
140 #endif | |
141 static void *png_zalloc(void *opaque, unsigned int items, unsigned int size) | |
142 { | |
2422 | 143 if(items >= UINT_MAX / size) |
144 return NULL; | |
2342 | 145 return av_malloc(items * size); |
146 } | |
147 | |
148 static void png_zfree(void *opaque, void *ptr) | |
149 { | |
150 av_free(ptr); | |
151 } | |
152 | |
153 static int png_get_nb_channels(int color_type) | |
154 { | |
155 int channels; | |
156 channels = 1; | |
157 if ((color_type & (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)) == | |
158 PNG_COLOR_MASK_COLOR) | |
159 channels = 3; | |
160 if (color_type & PNG_COLOR_MASK_ALPHA) | |
161 channels++; | |
162 return channels; | |
163 } | |
164 | |
165 /* compute the row size of an interleaved pass */ | |
166 static int png_pass_row_size(int pass, int bits_per_pixel, int width) | |
167 { | |
168 int shift, xmin, pass_width; | |
169 | |
170 xmin = png_pass_xmin[pass]; | |
171 if (width <= xmin) | |
172 return 0; | |
173 shift = png_pass_xshift[pass]; | |
174 pass_width = (width - xmin + (1 << shift) - 1) >> shift; | |
175 return (pass_width * bits_per_pixel + 7) >> 3; | |
176 } | |
177 | |
178 /* NOTE: we try to construct a good looking image at each pass. width | |
179 is the original image width. We also do pixel format convertion at | |
180 this stage */ | |
181 static void png_put_interlaced_row(uint8_t *dst, int width, | |
182 int bits_per_pixel, int pass, | |
183 int color_type, const uint8_t *src) | |
184 { | |
185 int x, mask, dsp_mask, j, src_x, b, bpp; | |
186 uint8_t *d; | |
187 const uint8_t *s; | |
188 | |
189 mask = png_pass_mask[pass]; | |
190 dsp_mask = png_pass_dsp_mask[pass]; | |
191 switch(bits_per_pixel) { | |
192 case 1: | |
193 /* we must intialize the line to zero before writing to it */ | |
194 if (pass == 0) | |
195 memset(dst, 0, (width + 7) >> 3); | |
196 src_x = 0; | |
197 for(x = 0; x < width; x++) { | |
198 j = (x & 7); | |
199 if ((dsp_mask << j) & 0x80) { | |
200 b = (src[src_x >> 3] >> (7 - (src_x & 7))) & 1; | |
201 dst[x >> 3] |= b << (7 - j); | |
202 } | |
203 if ((mask << j) & 0x80) | |
204 src_x++; | |
205 } | |
206 break; | |
207 default: | |
208 bpp = bits_per_pixel >> 3; | |
209 d = dst; | |
210 s = src; | |
211 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { | |
212 for(x = 0; x < width; x++) { | |
213 j = x & 7; | |
214 if ((dsp_mask << j) & 0x80) { | |
215 *(uint32_t *)d = (s[3] << 24) | (s[0] << 16) | (s[1] << 8) | s[2]; | |
216 } | |
217 d += bpp; | |
218 if ((mask << j) & 0x80) | |
219 s += bpp; | |
220 } | |
221 } else { | |
222 for(x = 0; x < width; x++) { | |
223 j = x & 7; | |
224 if ((dsp_mask << j) & 0x80) { | |
225 memcpy(d, s, bpp); | |
226 } | |
227 d += bpp; | |
228 if ((mask << j) & 0x80) | |
229 s += bpp; | |
230 } | |
231 } | |
232 break; | |
233 } | |
234 } | |
235 | |
236 static void png_get_interlaced_row(uint8_t *dst, int row_size, | |
237 int bits_per_pixel, int pass, | |
238 const uint8_t *src, int width) | |
239 { | |
240 int x, mask, dst_x, j, b, bpp; | |
241 uint8_t *d; | |
242 const uint8_t *s; | |
243 | |
244 mask = png_pass_mask[pass]; | |
245 switch(bits_per_pixel) { | |
246 case 1: | |
247 memset(dst, 0, row_size); | |
248 dst_x = 0; | |
249 for(x = 0; x < width; x++) { | |
250 j = (x & 7); | |
251 if ((mask << j) & 0x80) { | |
252 b = (src[x >> 3] >> (7 - j)) & 1; | |
253 dst[dst_x >> 3] |= b << (7 - (dst_x & 7)); | |
254 dst_x++; | |
255 } | |
256 } | |
257 break; | |
258 default: | |
259 bpp = bits_per_pixel >> 3; | |
260 d = dst; | |
261 s = src; | |
262 for(x = 0; x < width; x++) { | |
263 j = x & 7; | |
264 if ((mask << j) & 0x80) { | |
265 memcpy(d, s, bpp); | |
266 d += bpp; | |
267 } | |
268 s += bpp; | |
269 } | |
270 break; | |
271 } | |
272 } | |
273 | |
274 /* XXX: optimize */ | |
275 /* NOTE: 'dst' can be equal to 'last' */ | |
276 static void png_filter_row(uint8_t *dst, int filter_type, | |
277 uint8_t *src, uint8_t *last, int size, int bpp) | |
278 { | |
279 int i, p; | |
280 | |
281 switch(filter_type) { | |
282 case PNG_FILTER_VALUE_NONE: | |
283 memcpy(dst, src, size); | |
284 break; | |
285 case PNG_FILTER_VALUE_SUB: | |
286 for(i = 0; i < bpp; i++) { | |
287 dst[i] = src[i]; | |
288 } | |
289 for(i = bpp; i < size; i++) { | |
290 p = dst[i - bpp]; | |
291 dst[i] = p + src[i]; | |
292 } | |
293 break; | |
294 case PNG_FILTER_VALUE_UP: | |
295 for(i = 0; i < size; i++) { | |
296 p = last[i]; | |
297 dst[i] = p + src[i]; | |
298 } | |
299 break; | |
300 case PNG_FILTER_VALUE_AVG: | |
301 for(i = 0; i < bpp; i++) { | |
302 p = (last[i] >> 1); | |
303 dst[i] = p + src[i]; | |
304 } | |
305 for(i = bpp; i < size; i++) { | |
306 p = ((dst[i - bpp] + last[i]) >> 1); | |
307 dst[i] = p + src[i]; | |
308 } | |
309 break; | |
310 case PNG_FILTER_VALUE_PAETH: | |
311 for(i = 0; i < bpp; i++) { | |
312 p = last[i]; | |
313 dst[i] = p + src[i]; | |
314 } | |
315 for(i = bpp; i < size; i++) { | |
316 int a, b, c, pa, pb, pc; | |
317 | |
318 a = dst[i - bpp]; | |
319 b = last[i]; | |
320 c = last[i - bpp]; | |
321 | |
322 p = b - c; | |
323 pc = a - c; | |
324 | |
325 pa = abs(p); | |
326 pb = abs(pc); | |
327 pc = abs(p + pc); | |
328 | |
329 if (pa <= pb && pa <= pc) | |
330 p = a; | |
331 else if (pb <= pc) | |
332 p = b; | |
333 else | |
334 p = c; | |
335 dst[i] = p + src[i]; | |
336 } | |
337 break; | |
338 } | |
339 } | |
340 | |
341 static void convert_from_rgba32(uint8_t *dst, const uint8_t *src, int width) | |
342 { | |
343 uint8_t *d; | |
344 int j; | |
345 unsigned int v; | |
346 | |
347 d = dst; | |
348 for(j = 0; j < width; j++) { | |
349 v = ((uint32_t *)src)[j]; | |
350 d[0] = v >> 16; | |
351 d[1] = v >> 8; | |
352 d[2] = v; | |
353 d[3] = v >> 24; | |
354 d += 4; | |
355 } | |
356 } | |
357 | |
358 static void convert_to_rgba32(uint8_t *dst, const uint8_t *src, int width) | |
359 { | |
360 int j; | |
361 unsigned int r, g, b, a; | |
362 | |
363 for(j = 0;j < width; j++) { | |
364 r = src[0]; | |
365 g = src[1]; | |
366 b = src[2]; | |
367 a = src[3]; | |
368 *(uint32_t *)dst = (a << 24) | (r << 16) | (g << 8) | b; | |
369 dst += 4; | |
370 src += 4; | |
371 } | |
372 } | |
373 | |
374 /* process exactly one decompressed row */ | |
375 static void png_handle_row(PNGContext *s) | |
376 { | |
377 uint8_t *ptr, *last_row; | |
378 int got_line; | |
379 | |
380 if (!s->interlace_type) { | |
381 ptr = s->image_buf + s->image_linesize * s->y; | |
382 /* need to swap bytes correctly for RGB_ALPHA */ | |
383 if (s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { | |
384 png_filter_row(s->tmp_row, s->crow_buf[0], s->crow_buf + 1, | |
385 s->last_row, s->row_size, s->bpp); | |
386 memcpy(s->last_row, s->tmp_row, s->row_size); | |
387 convert_to_rgba32(ptr, s->tmp_row, s->width); | |
388 } else { | |
389 /* in normal case, we avoid one copy */ | |
390 if (s->y == 0) | |
391 last_row = s->last_row; | |
392 else | |
393 last_row = ptr - s->image_linesize; | |
394 | |
395 png_filter_row(ptr, s->crow_buf[0], s->crow_buf + 1, | |
396 last_row, s->row_size, s->bpp); | |
397 } | |
398 s->y++; | |
399 if (s->y == s->height) { | |
400 s->state |= PNG_ALLIMAGE; | |
401 } | |
402 } else { | |
403 got_line = 0; | |
404 for(;;) { | |
405 ptr = s->image_buf + s->image_linesize * s->y; | |
406 if ((png_pass_ymask[s->pass] << (s->y & 7)) & 0x80) { | |
407 /* if we already read one row, it is time to stop to | |
408 wait for the next one */ | |
409 if (got_line) | |
410 break; | |
411 png_filter_row(s->tmp_row, s->crow_buf[0], s->crow_buf + 1, | |
412 s->last_row, s->pass_row_size, s->bpp); | |
413 memcpy(s->last_row, s->tmp_row, s->pass_row_size); | |
414 got_line = 1; | |
415 } | |
416 if ((png_pass_dsp_ymask[s->pass] << (s->y & 7)) & 0x80) { | |
417 /* NOTE: rgba32 is handled directly in png_put_interlaced_row */ | |
418 png_put_interlaced_row(ptr, s->width, s->bits_per_pixel, s->pass, | |
419 s->color_type, s->last_row); | |
420 } | |
421 s->y++; | |
422 if (s->y == s->height) { | |
423 for(;;) { | |
424 if (s->pass == NB_PASSES - 1) { | |
425 s->state |= PNG_ALLIMAGE; | |
426 goto the_end; | |
427 } else { | |
428 s->pass++; | |
429 s->y = 0; | |
430 s->pass_row_size = png_pass_row_size(s->pass, | |
431 s->bits_per_pixel, | |
432 s->width); | |
433 s->crow_size = s->pass_row_size + 1; | |
434 if (s->pass_row_size != 0) | |
435 break; | |
436 /* skip pass if empty row */ | |
437 } | |
438 } | |
439 } | |
440 } | |
441 the_end: ; | |
442 } | |
443 } | |
444 | |
445 static int png_decode_idat(PNGContext *s, int length) | |
446 { | |
447 int ret; | |
448 s->zstream.avail_in = length; | |
449 s->zstream.next_in = s->bytestream; | |
450 s->bytestream += length; | |
451 | |
452 if(s->bytestream > s->bytestream_end) | |
453 return -1; | |
454 | |
455 /* decode one line if possible */ | |
456 while (s->zstream.avail_in > 0) { | |
457 ret = inflate(&s->zstream, Z_PARTIAL_FLUSH); | |
458 if (ret != Z_OK && ret != Z_STREAM_END) { | |
459 return -1; | |
460 } | |
461 if (s->zstream.avail_out == 0) { | |
462 if (!(s->state & PNG_ALLIMAGE)) { | |
463 png_handle_row(s); | |
464 } | |
465 s->zstream.avail_out = s->crow_size; | |
466 s->zstream.next_out = s->crow_buf; | |
467 } | |
468 } | |
469 return 0; | |
470 } | |
471 | |
472 static int decode_frame(AVCodecContext *avctx, | |
473 void *data, int *data_size, | |
474 uint8_t *buf, int buf_size) | |
475 { | |
476 PNGContext * const s = avctx->priv_data; | |
477 AVFrame *picture = data; | |
478 AVFrame * const p= (AVFrame*)&s->picture; | |
479 uint32_t tag, length; | |
480 int ret, crc; | |
481 | |
482 s->bytestream_start= | |
483 s->bytestream= buf; | |
484 s->bytestream_end= buf + buf_size; | |
485 | |
486 /* check signature */ | |
487 if (memcmp(s->bytestream, pngsig, 8) != 0) | |
488 return -1; | |
489 s->bytestream+= 8; | |
490 s->y= | |
491 s->state=0; | |
492 // memset(s, 0, sizeof(PNGContext)); | |
493 /* init the zlib */ | |
494 s->zstream.zalloc = png_zalloc; | |
495 s->zstream.zfree = png_zfree; | |
496 s->zstream.opaque = NULL; | |
497 ret = inflateInit(&s->zstream); | |
498 if (ret != Z_OK) | |
499 return -1; | |
500 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
|
501 int tag32; |
2342 | 502 if (s->bytestream >= s->bytestream_end) |
503 goto fail; | |
504 length = get32(&s->bytestream); | |
505 if (length > 0x7fffffff) | |
506 goto fail; | |
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
|
507 tag32 = get32(&s->bytestream); |
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
|
508 tag = bswap_32(tag32); |
2342 | 509 #ifdef DEBUG |
510 printf("png: tag=%c%c%c%c length=%u\n", | |
511 (tag & 0xff), | |
512 ((tag >> 8) & 0xff), | |
513 ((tag >> 16) & 0xff), | |
514 ((tag >> 24) & 0xff), length); | |
515 #endif | |
516 switch(tag) { | |
517 case MKTAG('I', 'H', 'D', 'R'): | |
518 if (length != 13) | |
519 goto fail; | |
520 s->width = get32(&s->bytestream); | |
521 s->height = get32(&s->bytestream); | |
2422 | 522 if(avcodec_check_dimensions(avctx, s->width, s->height)){ |
523 s->width= s->height= 0; | |
524 goto fail; | |
525 } | |
2342 | 526 s->bit_depth = *s->bytestream++; |
527 s->color_type = *s->bytestream++; | |
528 s->compression_type = *s->bytestream++; | |
529 s->filter_type = *s->bytestream++; | |
530 s->interlace_type = *s->bytestream++; | |
531 crc = get32(&s->bytestream); | |
532 s->state |= PNG_IHDR; | |
533 #ifdef DEBUG | |
534 printf("width=%d height=%d depth=%d color_type=%d compression_type=%d filter_type=%d interlace_type=%d\n", | |
535 s->width, s->height, s->bit_depth, s->color_type, | |
536 s->compression_type, s->filter_type, s->interlace_type); | |
537 #endif | |
538 break; | |
539 case MKTAG('I', 'D', 'A', 'T'): | |
540 if (!(s->state & PNG_IHDR)) | |
541 goto fail; | |
542 if (!(s->state & PNG_IDAT)) { | |
543 /* init image info */ | |
544 avctx->width = s->width; | |
545 avctx->height = s->height; | |
546 | |
547 s->channels = png_get_nb_channels(s->color_type); | |
548 s->bits_per_pixel = s->bit_depth * s->channels; | |
549 s->bpp = (s->bits_per_pixel + 7) >> 3; | |
550 s->row_size = (avctx->width * s->bits_per_pixel + 7) >> 3; | |
551 | |
552 if (s->bit_depth == 8 && | |
553 s->color_type == PNG_COLOR_TYPE_RGB) { | |
554 avctx->pix_fmt = PIX_FMT_RGB24; | |
555 } else if (s->bit_depth == 8 && | |
556 s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { | |
557 avctx->pix_fmt = PIX_FMT_RGBA32; | |
558 } else if (s->bit_depth == 8 && | |
559 s->color_type == PNG_COLOR_TYPE_GRAY) { | |
560 avctx->pix_fmt = PIX_FMT_GRAY8; | |
561 } else if (s->bit_depth == 1 && | |
562 s->color_type == PNG_COLOR_TYPE_GRAY) { | |
563 avctx->pix_fmt = PIX_FMT_MONOBLACK; | |
564 } else if (s->color_type == PNG_COLOR_TYPE_PALETTE) { | |
565 avctx->pix_fmt = PIX_FMT_PAL8; | |
566 } else { | |
567 goto fail; | |
568 } | |
569 if(p->data[0]) | |
570 avctx->release_buffer(avctx, p); | |
571 | |
572 p->reference= 0; | |
573 if(avctx->get_buffer(avctx, p) < 0){ | |
574 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |
575 goto fail; | |
576 } | |
577 p->pict_type= FF_I_TYPE; | |
578 p->key_frame= 1; | |
579 p->interlaced_frame = !!s->interlace_type; | |
580 | |
581 /* compute the compressed row size */ | |
582 if (!s->interlace_type) { | |
583 s->crow_size = s->row_size + 1; | |
584 } else { | |
585 s->pass = 0; | |
586 s->pass_row_size = png_pass_row_size(s->pass, | |
587 s->bits_per_pixel, | |
588 s->width); | |
589 s->crow_size = s->pass_row_size + 1; | |
590 } | |
591 #ifdef DEBUG | |
592 printf("row_size=%d crow_size =%d\n", | |
593 s->row_size, s->crow_size); | |
594 #endif | |
595 s->image_buf = p->data[0]; | |
596 s->image_linesize = p->linesize[0]; | |
597 /* copy the palette if needed */ | |
598 if (s->color_type == PNG_COLOR_TYPE_PALETTE) | |
599 memcpy(p->data[1], s->palette, 256 * sizeof(uint32_t)); | |
600 /* empty row is used if differencing to the first row */ | |
601 s->last_row = av_mallocz(s->row_size); | |
602 if (!s->last_row) | |
603 goto fail; | |
604 if (s->interlace_type || | |
605 s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { | |
606 s->tmp_row = av_malloc(s->row_size); | |
607 if (!s->tmp_row) | |
608 goto fail; | |
609 } | |
610 /* compressed row */ | |
611 s->crow_buf = av_malloc(s->row_size + 1); | |
612 if (!s->crow_buf) | |
613 goto fail; | |
614 s->zstream.avail_out = s->crow_size; | |
615 s->zstream.next_out = s->crow_buf; | |
616 } | |
617 s->state |= PNG_IDAT; | |
618 if (png_decode_idat(s, length) < 0) | |
619 goto fail; | |
620 /* skip crc */ | |
621 crc = get32(&s->bytestream); | |
622 break; | |
623 case MKTAG('P', 'L', 'T', 'E'): | |
624 { | |
625 int n, i, r, g, b; | |
626 | |
627 if ((length % 3) != 0 || length > 256 * 3) | |
628 goto skip_tag; | |
629 /* read the palette */ | |
630 n = length / 3; | |
631 for(i=0;i<n;i++) { | |
632 r = *s->bytestream++; | |
633 g = *s->bytestream++; | |
634 b = *s->bytestream++; | |
635 s->palette[i] = (0xff << 24) | (r << 16) | (g << 8) | b; | |
636 } | |
637 for(;i<256;i++) { | |
638 s->palette[i] = (0xff << 24); | |
639 } | |
640 s->state |= PNG_PLTE; | |
641 crc = get32(&s->bytestream); | |
642 } | |
643 break; | |
644 case MKTAG('t', 'R', 'N', 'S'): | |
645 { | |
646 int v, i; | |
647 | |
648 /* read the transparency. XXX: Only palette mode supported */ | |
649 if (s->color_type != PNG_COLOR_TYPE_PALETTE || | |
650 length > 256 || | |
651 !(s->state & PNG_PLTE)) | |
652 goto skip_tag; | |
653 for(i=0;i<length;i++) { | |
654 v = *s->bytestream++; | |
655 s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24); | |
656 } | |
657 crc = get32(&s->bytestream); | |
658 } | |
659 break; | |
660 case MKTAG('I', 'E', 'N', 'D'): | |
661 if (!(s->state & PNG_ALLIMAGE)) | |
662 goto fail; | |
663 crc = get32(&s->bytestream); | |
664 goto exit_loop; | |
665 default: | |
666 /* skip tag */ | |
667 skip_tag: | |
668 s->bytestream += length + 4; | |
669 break; | |
670 } | |
671 } | |
672 exit_loop: | |
673 *picture= *(AVFrame*)&s->picture; | |
674 *data_size = sizeof(AVPicture); | |
675 | |
676 ret = s->bytestream - s->bytestream_start; | |
677 the_end: | |
678 inflateEnd(&s->zstream); | |
679 av_freep(&s->crow_buf); | |
680 av_freep(&s->last_row); | |
681 av_freep(&s->tmp_row); | |
682 return ret; | |
683 fail: | |
684 ret = -1; | |
685 goto the_end; | |
686 } | |
687 | |
688 static void png_write_chunk(uint8_t **f, uint32_t tag, | |
689 const uint8_t *buf, int length) | |
690 { | |
691 uint32_t crc; | |
692 uint8_t tagbuf[4]; | |
693 | |
694 put32(f, length); | |
695 crc = crc32(0, Z_NULL, 0); | |
696 tagbuf[0] = tag; | |
697 tagbuf[1] = tag >> 8; | |
698 tagbuf[2] = tag >> 16; | |
699 tagbuf[3] = tag >> 24; | |
700 crc = crc32(crc, tagbuf, 4); | |
701 put32(f, bswap_32(tag)); | |
702 if (length > 0) { | |
703 crc = crc32(crc, buf, length); | |
704 memcpy(*f, buf, length); | |
705 *f += length; | |
706 } | |
707 put32(f, crc); | |
708 } | |
709 | |
710 /* XXX: use avcodec generic function ? */ | |
711 static void to_be32(uint8_t *p, uint32_t v) | |
712 { | |
713 p[0] = v >> 24; | |
714 p[1] = v >> 16; | |
715 p[2] = v >> 8; | |
716 p[3] = v; | |
717 } | |
718 | |
719 /* XXX: do filtering */ | |
720 static int png_write_row(PNGContext *s, const uint8_t *data, int size) | |
721 { | |
722 int ret; | |
723 | |
724 s->zstream.avail_in = size; | |
725 s->zstream.next_in = (uint8_t *)data; | |
726 while (s->zstream.avail_in > 0) { | |
727 ret = deflate(&s->zstream, Z_NO_FLUSH); | |
728 if (ret != Z_OK) | |
729 return -1; | |
730 if (s->zstream.avail_out == 0) { | |
2422 | 731 if(s->bytestream_end - s->bytestream > IOBUF_SIZE + 100) |
732 png_write_chunk(&s->bytestream, MKTAG('I', 'D', 'A', 'T'), s->buf, IOBUF_SIZE); | |
2342 | 733 s->zstream.avail_out = IOBUF_SIZE; |
734 s->zstream.next_out = s->buf; | |
735 } | |
736 } | |
737 return 0; | |
738 } | |
739 | |
740 static int common_init(AVCodecContext *avctx){ | |
741 PNGContext *s = avctx->priv_data; | |
742 | |
743 avcodec_get_frame_defaults((AVFrame*)&s->picture); | |
744 avctx->coded_frame= (AVFrame*)&s->picture; | |
745 // s->avctx= avctx; | |
746 | |
747 return 0; | |
748 } | |
749 | |
750 static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){ | |
751 PNGContext *s = avctx->priv_data; | |
752 AVFrame *pict = data; | |
753 AVFrame * const p= (AVFrame*)&s->picture; | |
754 int bit_depth, color_type, y, len, row_size, ret, is_progressive; | |
755 int bits_per_pixel, pass_row_size; | |
756 uint8_t *ptr; | |
757 uint8_t *crow_buf = NULL; | |
758 uint8_t *tmp_buf = NULL; | |
759 | |
760 *p = *pict; | |
761 p->pict_type= FF_I_TYPE; | |
762 p->key_frame= 1; | |
763 | |
764 s->bytestream_start= | |
765 s->bytestream= buf; | |
766 s->bytestream_end= buf+buf_size; | |
767 | |
768 is_progressive = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT); | |
769 switch(avctx->pix_fmt) { | |
770 case PIX_FMT_RGBA32: | |
771 bit_depth = 8; | |
772 color_type = PNG_COLOR_TYPE_RGB_ALPHA; | |
773 break; | |
774 case PIX_FMT_RGB24: | |
775 bit_depth = 8; | |
776 color_type = PNG_COLOR_TYPE_RGB; | |
777 break; | |
778 case PIX_FMT_GRAY8: | |
779 bit_depth = 8; | |
780 color_type = PNG_COLOR_TYPE_GRAY; | |
781 break; | |
782 case PIX_FMT_MONOBLACK: | |
783 bit_depth = 1; | |
784 color_type = PNG_COLOR_TYPE_GRAY; | |
785 break; | |
786 case PIX_FMT_PAL8: | |
787 bit_depth = 8; | |
788 color_type = PNG_COLOR_TYPE_PALETTE; | |
789 break; | |
790 default: | |
791 return -1; | |
792 } | |
793 bits_per_pixel = png_get_nb_channels(color_type) * bit_depth; | |
794 row_size = (avctx->width * bits_per_pixel + 7) >> 3; | |
795 | |
796 s->zstream.zalloc = png_zalloc; | |
797 s->zstream.zfree = png_zfree; | |
798 s->zstream.opaque = NULL; | |
799 ret = deflateInit2(&s->zstream, Z_DEFAULT_COMPRESSION, | |
800 Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY); | |
801 if (ret != Z_OK) | |
802 return -1; | |
803 crow_buf = av_malloc(row_size + 1); | |
804 if (!crow_buf) | |
805 goto fail; | |
806 if (is_progressive) { | |
807 tmp_buf = av_malloc(row_size + 1); | |
808 if (!tmp_buf) | |
809 goto fail; | |
810 } | |
811 | |
812 /* write png header */ | |
813 memcpy(s->bytestream, pngsig, 8); | |
814 s->bytestream += 8; | |
815 | |
816 to_be32(s->buf, avctx->width); | |
817 to_be32(s->buf + 4, avctx->height); | |
818 s->buf[8] = bit_depth; | |
819 s->buf[9] = color_type; | |
820 s->buf[10] = 0; /* compression type */ | |
821 s->buf[11] = 0; /* filter type */ | |
822 s->buf[12] = is_progressive; /* interlace type */ | |
823 | |
824 png_write_chunk(&s->bytestream, MKTAG('I', 'H', 'D', 'R'), s->buf, 13); | |
825 | |
826 /* put the palette if needed */ | |
827 if (color_type == PNG_COLOR_TYPE_PALETTE) { | |
828 int has_alpha, alpha, i; | |
829 unsigned int v; | |
830 uint32_t *palette; | |
831 uint8_t *alpha_ptr; | |
832 | |
833 palette = (uint32_t *)p->data[1]; | |
834 ptr = s->buf; | |
835 alpha_ptr = s->buf + 256 * 3; | |
836 has_alpha = 0; | |
837 for(i = 0; i < 256; i++) { | |
838 v = palette[i]; | |
839 alpha = v >> 24; | |
840 if (alpha != 0xff) | |
841 has_alpha = 1; | |
842 *alpha_ptr++ = alpha; | |
843 ptr[0] = v >> 16; | |
844 ptr[1] = v >> 8; | |
845 ptr[2] = v; | |
846 ptr += 3; | |
847 } | |
848 png_write_chunk(&s->bytestream, MKTAG('P', 'L', 'T', 'E'), s->buf, 256 * 3); | |
849 if (has_alpha) { | |
850 png_write_chunk(&s->bytestream, MKTAG('t', 'R', 'N', 'S'), s->buf + 256 * 3, 256); | |
851 } | |
852 } | |
853 | |
854 /* now put each row */ | |
855 s->zstream.avail_out = IOBUF_SIZE; | |
856 s->zstream.next_out = s->buf; | |
857 if (is_progressive) { | |
858 uint8_t *ptr1; | |
859 int pass; | |
860 | |
861 for(pass = 0; pass < NB_PASSES; pass++) { | |
862 /* NOTE: a pass is completely omited if no pixels would be | |
863 output */ | |
864 pass_row_size = png_pass_row_size(pass, bits_per_pixel, avctx->width); | |
865 if (pass_row_size > 0) { | |
866 for(y = 0; y < avctx->height; y++) { | |
867 if ((png_pass_ymask[pass] << (y & 7)) & 0x80) { | |
868 ptr = p->data[0] + y * p->linesize[0]; | |
869 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { | |
870 convert_from_rgba32(tmp_buf, ptr, avctx->width); | |
871 ptr1 = tmp_buf; | |
872 } else { | |
873 ptr1 = ptr; | |
874 } | |
875 png_get_interlaced_row(crow_buf + 1, pass_row_size, | |
876 bits_per_pixel, pass, | |
877 ptr1, avctx->width); | |
878 crow_buf[0] = PNG_FILTER_VALUE_NONE; | |
879 png_write_row(s, crow_buf, pass_row_size + 1); | |
880 } | |
881 } | |
882 } | |
883 } | |
884 } else { | |
885 for(y = 0; y < avctx->height; y++) { | |
886 ptr = p->data[0] + y * p->linesize[0]; | |
887 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) | |
888 convert_from_rgba32(crow_buf + 1, ptr, avctx->width); | |
889 else | |
890 memcpy(crow_buf + 1, ptr, row_size); | |
891 crow_buf[0] = PNG_FILTER_VALUE_NONE; | |
892 png_write_row(s, crow_buf, row_size + 1); | |
893 } | |
894 } | |
895 /* compress last bytes */ | |
896 for(;;) { | |
897 ret = deflate(&s->zstream, Z_FINISH); | |
898 if (ret == Z_OK || ret == Z_STREAM_END) { | |
899 len = IOBUF_SIZE - s->zstream.avail_out; | |
2422 | 900 if (len > 0 && s->bytestream_end - s->bytestream > len + 100) { |
2342 | 901 png_write_chunk(&s->bytestream, MKTAG('I', 'D', 'A', 'T'), s->buf, len); |
902 } | |
903 s->zstream.avail_out = IOBUF_SIZE; | |
904 s->zstream.next_out = s->buf; | |
905 if (ret == Z_STREAM_END) | |
906 break; | |
907 } else { | |
908 goto fail; | |
909 } | |
910 } | |
911 png_write_chunk(&s->bytestream, MKTAG('I', 'E', 'N', 'D'), NULL, 0); | |
912 | |
913 ret = s->bytestream - s->bytestream_start; | |
914 the_end: | |
915 av_free(crow_buf); | |
916 av_free(tmp_buf); | |
917 deflateEnd(&s->zstream); | |
918 return ret; | |
919 fail: | |
920 ret = -1; | |
921 goto the_end; | |
922 } | |
923 | |
924 AVCodec png_decoder = { | |
925 "png", | |
926 CODEC_TYPE_VIDEO, | |
927 CODEC_ID_PNG, | |
928 sizeof(PNGContext), | |
929 common_init, | |
930 NULL, | |
931 NULL, //decode_end, | |
932 decode_frame, | |
933 0 /*CODEC_CAP_DR1*/ /*| CODEC_CAP_DRAW_HORIZ_BAND*/, | |
934 NULL | |
935 }; | |
936 | |
937 AVCodec png_encoder = { | |
938 "png", | |
939 CODEC_TYPE_VIDEO, | |
940 CODEC_ID_PNG, | |
941 sizeof(PNGContext), | |
942 common_init, | |
943 encode_frame, | |
944 NULL, //encode_end, | |
945 .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGBA32, PIX_FMT_PAL8, PIX_FMT_GRAY8, PIX_FMT_MONOBLACK, -1}, | |
946 }; | |
947 #endif |