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