00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "avcodec.h"
00022 #include "bytestream.h"
00023 #include "png.h"
00024
00025
00026
00027
00028
00029
00030 #include <zlib.h>
00031
00032
00033
00034 #define IOBUF_SIZE 4096
00035
00036 typedef struct PNGEncContext {
00037 uint8_t *bytestream;
00038 uint8_t *bytestream_start;
00039 uint8_t *bytestream_end;
00040 AVFrame picture;
00041
00042 z_stream zstream;
00043 uint8_t buf[IOBUF_SIZE];
00044 } PNGEncContext;
00045
00046 static void png_get_interlaced_row(uint8_t *dst, int row_size,
00047 int bits_per_pixel, int pass,
00048 const uint8_t *src, int width)
00049 {
00050 int x, mask, dst_x, j, b, bpp;
00051 uint8_t *d;
00052 const uint8_t *s;
00053
00054 mask = ff_png_pass_mask[pass];
00055 switch(bits_per_pixel) {
00056 case 1:
00057 memset(dst, 0, row_size);
00058 dst_x = 0;
00059 for(x = 0; x < width; x++) {
00060 j = (x & 7);
00061 if ((mask << j) & 0x80) {
00062 b = (src[x >> 3] >> (7 - j)) & 1;
00063 dst[dst_x >> 3] |= b << (7 - (dst_x & 7));
00064 dst_x++;
00065 }
00066 }
00067 break;
00068 default:
00069 bpp = bits_per_pixel >> 3;
00070 d = dst;
00071 s = src;
00072 for(x = 0; x < width; x++) {
00073 j = x & 7;
00074 if ((mask << j) & 0x80) {
00075 memcpy(d, s, bpp);
00076 d += bpp;
00077 }
00078 s += bpp;
00079 }
00080 break;
00081 }
00082 }
00083
00084 static void convert_from_rgb32(uint8_t *dst, const uint8_t *src, int width)
00085 {
00086 uint8_t *d;
00087 int j;
00088 unsigned int v;
00089
00090 d = dst;
00091 for(j = 0; j < width; j++) {
00092 v = ((const uint32_t *)src)[j];
00093 d[0] = v >> 16;
00094 d[1] = v >> 8;
00095 d[2] = v;
00096 d[3] = v >> 24;
00097 d += 4;
00098 }
00099 }
00100
00101 static void png_write_chunk(uint8_t **f, uint32_t tag,
00102 const uint8_t *buf, int length)
00103 {
00104 uint32_t crc;
00105 uint8_t tagbuf[4];
00106
00107 bytestream_put_be32(f, length);
00108 crc = crc32(0, Z_NULL, 0);
00109 AV_WL32(tagbuf, tag);
00110 crc = crc32(crc, tagbuf, 4);
00111 bytestream_put_be32(f, bswap_32(tag));
00112 if (length > 0) {
00113 crc = crc32(crc, buf, length);
00114 memcpy(*f, buf, length);
00115 *f += length;
00116 }
00117 bytestream_put_be32(f, crc);
00118 }
00119
00120
00121 static int png_write_row(PNGEncContext *s, const uint8_t *data, int size)
00122 {
00123 int ret;
00124
00125 s->zstream.avail_in = size;
00126 s->zstream.next_in = (uint8_t *)data;
00127 while (s->zstream.avail_in > 0) {
00128 ret = deflate(&s->zstream, Z_NO_FLUSH);
00129 if (ret != Z_OK)
00130 return -1;
00131 if (s->zstream.avail_out == 0) {
00132 if(s->bytestream_end - s->bytestream > IOBUF_SIZE + 100)
00133 png_write_chunk(&s->bytestream, MKTAG('I', 'D', 'A', 'T'), s->buf, IOBUF_SIZE);
00134 s->zstream.avail_out = IOBUF_SIZE;
00135 s->zstream.next_out = s->buf;
00136 }
00137 }
00138 return 0;
00139 }
00140
00141 static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){
00142 PNGEncContext *s = avctx->priv_data;
00143 AVFrame *pict = data;
00144 AVFrame * const p= (AVFrame*)&s->picture;
00145 int bit_depth, color_type, y, len, row_size, ret, is_progressive;
00146 int bits_per_pixel, pass_row_size;
00147 int compression_level;
00148 uint8_t *ptr;
00149 uint8_t *crow_buf = NULL;
00150 uint8_t *tmp_buf = NULL;
00151
00152 *p = *pict;
00153 p->pict_type= FF_I_TYPE;
00154 p->key_frame= 1;
00155
00156 s->bytestream_start=
00157 s->bytestream= buf;
00158 s->bytestream_end= buf+buf_size;
00159
00160 is_progressive = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT);
00161 switch(avctx->pix_fmt) {
00162 case PIX_FMT_RGB32:
00163 bit_depth = 8;
00164 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
00165 break;
00166 case PIX_FMT_RGB24:
00167 bit_depth = 8;
00168 color_type = PNG_COLOR_TYPE_RGB;
00169 break;
00170 case PIX_FMT_GRAY8:
00171 bit_depth = 8;
00172 color_type = PNG_COLOR_TYPE_GRAY;
00173 break;
00174 case PIX_FMT_MONOBLACK:
00175 bit_depth = 1;
00176 color_type = PNG_COLOR_TYPE_GRAY;
00177 break;
00178 case PIX_FMT_PAL8:
00179 bit_depth = 8;
00180 color_type = PNG_COLOR_TYPE_PALETTE;
00181 break;
00182 default:
00183 return -1;
00184 }
00185 bits_per_pixel = ff_png_get_nb_channels(color_type) * bit_depth;
00186 row_size = (avctx->width * bits_per_pixel + 7) >> 3;
00187
00188 s->zstream.zalloc = ff_png_zalloc;
00189 s->zstream.zfree = ff_png_zfree;
00190 s->zstream.opaque = NULL;
00191 compression_level = avctx->compression_level == FF_COMPRESSION_DEFAULT ?
00192 Z_DEFAULT_COMPRESSION :
00193 av_clip(avctx->compression_level, 0, 9);
00194 ret = deflateInit2(&s->zstream, compression_level,
00195 Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY);
00196 if (ret != Z_OK)
00197 return -1;
00198 crow_buf = av_malloc(row_size + 1);
00199 if (!crow_buf)
00200 goto fail;
00201 if (is_progressive) {
00202 tmp_buf = av_malloc(row_size + 1);
00203 if (!tmp_buf)
00204 goto fail;
00205 }
00206
00207
00208 memcpy(s->bytestream, ff_pngsig, 8);
00209 s->bytestream += 8;
00210
00211 AV_WB32(s->buf, avctx->width);
00212 AV_WB32(s->buf + 4, avctx->height);
00213 s->buf[8] = bit_depth;
00214 s->buf[9] = color_type;
00215 s->buf[10] = 0;
00216 s->buf[11] = 0;
00217 s->buf[12] = is_progressive;
00218
00219 png_write_chunk(&s->bytestream, MKTAG('I', 'H', 'D', 'R'), s->buf, 13);
00220
00221
00222 if (color_type == PNG_COLOR_TYPE_PALETTE) {
00223 int has_alpha, alpha, i;
00224 unsigned int v;
00225 uint32_t *palette;
00226 uint8_t *alpha_ptr;
00227
00228 palette = (uint32_t *)p->data[1];
00229 ptr = s->buf;
00230 alpha_ptr = s->buf + 256 * 3;
00231 has_alpha = 0;
00232 for(i = 0; i < 256; i++) {
00233 v = palette[i];
00234 alpha = v >> 24;
00235 if (alpha && alpha != 0xff)
00236 has_alpha = 1;
00237 *alpha_ptr++ = alpha;
00238 bytestream_put_be24(&ptr, v);
00239 }
00240 png_write_chunk(&s->bytestream, MKTAG('P', 'L', 'T', 'E'), s->buf, 256 * 3);
00241 if (has_alpha) {
00242 png_write_chunk(&s->bytestream, MKTAG('t', 'R', 'N', 'S'), s->buf + 256 * 3, 256);
00243 }
00244 }
00245
00246
00247 s->zstream.avail_out = IOBUF_SIZE;
00248 s->zstream.next_out = s->buf;
00249 if (is_progressive) {
00250 uint8_t *ptr1;
00251 int pass;
00252
00253 for(pass = 0; pass < NB_PASSES; pass++) {
00254
00255
00256 pass_row_size = ff_png_pass_row_size(pass, bits_per_pixel, avctx->width);
00257 if (pass_row_size > 0) {
00258 for(y = 0; y < avctx->height; y++) {
00259 if ((ff_png_pass_ymask[pass] << (y & 7)) & 0x80) {
00260 ptr = p->data[0] + y * p->linesize[0];
00261 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
00262 convert_from_rgb32(tmp_buf, ptr, avctx->width);
00263 ptr1 = tmp_buf;
00264 } else {
00265 ptr1 = ptr;
00266 }
00267 png_get_interlaced_row(crow_buf + 1, pass_row_size,
00268 bits_per_pixel, pass,
00269 ptr1, avctx->width);
00270 crow_buf[0] = PNG_FILTER_VALUE_NONE;
00271 png_write_row(s, crow_buf, pass_row_size + 1);
00272 }
00273 }
00274 }
00275 }
00276 } else {
00277 for(y = 0; y < avctx->height; y++) {
00278 ptr = p->data[0] + y * p->linesize[0];
00279 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
00280 convert_from_rgb32(crow_buf + 1, ptr, avctx->width);
00281 else
00282 memcpy(crow_buf + 1, ptr, row_size);
00283 crow_buf[0] = PNG_FILTER_VALUE_NONE;
00284 png_write_row(s, crow_buf, row_size + 1);
00285 }
00286 }
00287
00288 for(;;) {
00289 ret = deflate(&s->zstream, Z_FINISH);
00290 if (ret == Z_OK || ret == Z_STREAM_END) {
00291 len = IOBUF_SIZE - s->zstream.avail_out;
00292 if (len > 0 && s->bytestream_end - s->bytestream > len + 100) {
00293 png_write_chunk(&s->bytestream, MKTAG('I', 'D', 'A', 'T'), s->buf, len);
00294 }
00295 s->zstream.avail_out = IOBUF_SIZE;
00296 s->zstream.next_out = s->buf;
00297 if (ret == Z_STREAM_END)
00298 break;
00299 } else {
00300 goto fail;
00301 }
00302 }
00303 png_write_chunk(&s->bytestream, MKTAG('I', 'E', 'N', 'D'), NULL, 0);
00304
00305 ret = s->bytestream - s->bytestream_start;
00306 the_end:
00307 av_free(crow_buf);
00308 av_free(tmp_buf);
00309 deflateEnd(&s->zstream);
00310 return ret;
00311 fail:
00312 ret = -1;
00313 goto the_end;
00314 }
00315
00316 static int png_enc_init(AVCodecContext *avctx){
00317 PNGEncContext *s = avctx->priv_data;
00318
00319 avcodec_get_frame_defaults((AVFrame*)&s->picture);
00320 avctx->coded_frame= (AVFrame*)&s->picture;
00321
00322 return 0;
00323 }
00324
00325 AVCodec png_encoder = {
00326 "png",
00327 CODEC_TYPE_VIDEO,
00328 CODEC_ID_PNG,
00329 sizeof(PNGEncContext),
00330 png_enc_init,
00331 encode_frame,
00332 NULL,
00333 .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB32, PIX_FMT_PAL8, PIX_FMT_GRAY8, PIX_FMT_MONOBLACK, -1},
00334 };