|
|
@ -18,6 +18,7 @@ |
|
|
|
* License along with Libav; if not, write to the Free Software |
|
|
|
* License along with Libav; if not, write to the Free Software |
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
#include "avcodec.h" |
|
|
|
#include "avcodec.h" |
|
|
|
#include "bytestream.h" |
|
|
|
#include "bytestream.h" |
|
|
|
#include "dsputil.h" |
|
|
|
#include "dsputil.h" |
|
|
@ -82,7 +83,8 @@ static void png_get_interlaced_row(uint8_t *dst, int row_size, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void sub_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp) |
|
|
|
static void sub_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, |
|
|
|
|
|
|
|
int w, int bpp) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int i; |
|
|
|
int i; |
|
|
|
for (i = 0; i < w; i++) { |
|
|
|
for (i = 0; i < w; i++) { |
|
|
@ -218,7 +220,8 @@ static int png_write_row(PNGEncContext *s, const uint8_t *data, int size) |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
if (s->zstream.avail_out == 0) { |
|
|
|
if (s->zstream.avail_out == 0) { |
|
|
|
if (s->bytestream_end - s->bytestream > IOBUF_SIZE + 100) |
|
|
|
if (s->bytestream_end - s->bytestream > IOBUF_SIZE + 100) |
|
|
|
png_write_chunk(&s->bytestream, MKTAG('I', 'D', 'A', 'T'), s->buf, IOBUF_SIZE); |
|
|
|
png_write_chunk(&s->bytestream, |
|
|
|
|
|
|
|
MKTAG('I', 'D', 'A', 'T'), s->buf, IOBUF_SIZE); |
|
|
|
s->zstream.avail_out = IOBUF_SIZE; |
|
|
|
s->zstream.avail_out = IOBUF_SIZE; |
|
|
|
s->zstream.next_out = s->buf; |
|
|
|
s->zstream.next_out = s->buf; |
|
|
|
} |
|
|
|
} |
|
|
@ -234,8 +237,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
|
|
|
int bit_depth, color_type, y, len, row_size, ret, is_progressive; |
|
|
|
int bit_depth, color_type, y, len, row_size, ret, is_progressive; |
|
|
|
int bits_per_pixel, pass_row_size, enc_row_size, max_packet_size; |
|
|
|
int bits_per_pixel, pass_row_size, enc_row_size, max_packet_size; |
|
|
|
int compression_level; |
|
|
|
int compression_level; |
|
|
|
uint8_t *ptr, *top; |
|
|
|
uint8_t *ptr, *top, *crow_buf, *crow; |
|
|
|
uint8_t *crow_base = NULL, *crow_buf, *crow; |
|
|
|
uint8_t *crow_base = NULL; |
|
|
|
uint8_t *progressive_buf = NULL; |
|
|
|
uint8_t *progressive_buf = NULL; |
|
|
|
uint8_t *rgba_buf = NULL; |
|
|
|
uint8_t *rgba_buf = NULL; |
|
|
|
uint8_t *top_buf = NULL; |
|
|
|
uint8_t *top_buf = NULL; |
|
|
@ -275,9 +278,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
|
|
|
s->zstream.zalloc = ff_png_zalloc; |
|
|
|
s->zstream.zalloc = ff_png_zalloc; |
|
|
|
s->zstream.zfree = ff_png_zfree; |
|
|
|
s->zstream.zfree = ff_png_zfree; |
|
|
|
s->zstream.opaque = NULL; |
|
|
|
s->zstream.opaque = NULL; |
|
|
|
compression_level = avctx->compression_level == FF_COMPRESSION_DEFAULT ? |
|
|
|
compression_level = avctx->compression_level == FF_COMPRESSION_DEFAULT |
|
|
|
Z_DEFAULT_COMPRESSION : |
|
|
|
? Z_DEFAULT_COMPRESSION |
|
|
|
av_clip(avctx->compression_level, 0, 9); |
|
|
|
: av_clip(avctx->compression_level, 0, 9); |
|
|
|
ret = deflateInit2(&s->zstream, compression_level, |
|
|
|
ret = deflateInit2(&s->zstream, compression_level, |
|
|
|
Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY); |
|
|
|
Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY); |
|
|
|
if (ret != Z_OK) |
|
|
|
if (ret != Z_OK) |
|
|
@ -301,7 +304,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
|
|
|
crow_base = av_malloc((row_size + 32) << (s->filter_type == PNG_FILTER_VALUE_MIXED)); |
|
|
|
crow_base = av_malloc((row_size + 32) << (s->filter_type == PNG_FILTER_VALUE_MIXED)); |
|
|
|
if (!crow_base) |
|
|
|
if (!crow_base) |
|
|
|
goto fail; |
|
|
|
goto fail; |
|
|
|
crow_buf = crow_base + 15; // pixel data should be aligned, but there's a control byte before it
|
|
|
|
// pixel data should be aligned, but there's a control byte before it
|
|
|
|
|
|
|
|
crow_buf = crow_base + 15; |
|
|
|
if (is_progressive) { |
|
|
|
if (is_progressive) { |
|
|
|
progressive_buf = av_malloc(row_size + 1); |
|
|
|
progressive_buf = av_malloc(row_size + 1); |
|
|
|
if (!progressive_buf) |
|
|
|
if (!progressive_buf) |
|
|
@ -351,9 +355,11 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
|
|
|
*alpha_ptr++ = alpha; |
|
|
|
*alpha_ptr++ = alpha; |
|
|
|
bytestream_put_be24(&ptr, v); |
|
|
|
bytestream_put_be24(&ptr, v); |
|
|
|
} |
|
|
|
} |
|
|
|
png_write_chunk(&s->bytestream, MKTAG('P', 'L', 'T', 'E'), s->buf, 256 * 3); |
|
|
|
png_write_chunk(&s->bytestream, |
|
|
|
|
|
|
|
MKTAG('P', 'L', 'T', 'E'), s->buf, 256 * 3); |
|
|
|
if (has_alpha) { |
|
|
|
if (has_alpha) { |
|
|
|
png_write_chunk(&s->bytestream, MKTAG('t', 'R', 'N', 'S'), s->buf + 256 * 3, 256); |
|
|
|
png_write_chunk(&s->bytestream, |
|
|
|
|
|
|
|
MKTAG('t', 'R', 'N', 'S'), s->buf + 256 * 3, 256); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -365,11 +371,11 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
|
|
|
|
|
|
|
|
|
|
|
for (pass = 0; pass < NB_PASSES; pass++) { |
|
|
|
for (pass = 0; pass < NB_PASSES; pass++) { |
|
|
|
/* NOTE: a pass is completely omitted if no pixels would be
|
|
|
|
/* NOTE: a pass is completely omitted if no pixels would be
|
|
|
|
output */ |
|
|
|
* output */ |
|
|
|
pass_row_size = ff_png_pass_row_size(pass, bits_per_pixel, avctx->width); |
|
|
|
pass_row_size = ff_png_pass_row_size(pass, bits_per_pixel, avctx->width); |
|
|
|
if (pass_row_size > 0) { |
|
|
|
if (pass_row_size > 0) { |
|
|
|
top = NULL; |
|
|
|
top = NULL; |
|
|
|
for(y = 0; y < avctx->height; y++) { |
|
|
|
for (y = 0; y < avctx->height; y++) |
|
|
|
if ((ff_png_pass_ymask[pass] << (y & 7)) & 0x80) { |
|
|
|
if ((ff_png_pass_ymask[pass] << (y & 7)) & 0x80) { |
|
|
|
ptr = p->data[0] + y * p->linesize[0]; |
|
|
|
ptr = p->data[0] + y * p->linesize[0]; |
|
|
|
FFSWAP(uint8_t *, progressive_buf, top_buf); |
|
|
|
FFSWAP(uint8_t *, progressive_buf, top_buf); |
|
|
@ -380,13 +386,13 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
|
|
|
png_get_interlaced_row(progressive_buf, pass_row_size, |
|
|
|
png_get_interlaced_row(progressive_buf, pass_row_size, |
|
|
|
bits_per_pixel, pass, |
|
|
|
bits_per_pixel, pass, |
|
|
|
ptr, avctx->width); |
|
|
|
ptr, avctx->width); |
|
|
|
crow = png_choose_filter(s, crow_buf, progressive_buf, top, pass_row_size, bits_per_pixel>>3); |
|
|
|
crow = png_choose_filter(s, crow_buf, progressive_buf, |
|
|
|
|
|
|
|
top, pass_row_size, bits_per_pixel >> 3); |
|
|
|
png_write_row(s, crow, pass_row_size + 1); |
|
|
|
png_write_row(s, crow, pass_row_size + 1); |
|
|
|
top = progressive_buf; |
|
|
|
top = progressive_buf; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
top = NULL; |
|
|
|
top = NULL; |
|
|
|
for (y = 0; y < avctx->height; y++) { |
|
|
|
for (y = 0; y < avctx->height; y++) { |
|
|
@ -396,7 +402,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
|
|
|
convert_from_rgb32(rgba_buf, ptr, avctx->width); |
|
|
|
convert_from_rgb32(rgba_buf, ptr, avctx->width); |
|
|
|
ptr = rgba_buf; |
|
|
|
ptr = rgba_buf; |
|
|
|
} |
|
|
|
} |
|
|
|
crow = png_choose_filter(s, crow_buf, ptr, top, row_size, bits_per_pixel>>3); |
|
|
|
crow = png_choose_filter(s, crow_buf, ptr, top, |
|
|
|
|
|
|
|
row_size, bits_per_pixel >> 3); |
|
|
|
png_write_row(s, crow, row_size + 1); |
|
|
|
png_write_row(s, crow, row_size + 1); |
|
|
|
top = ptr; |
|
|
|
top = ptr; |
|
|
|
} |
|
|
|
} |
|
|
@ -436,7 +443,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
|
|
|
goto the_end; |
|
|
|
goto the_end; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static av_cold int png_enc_init(AVCodecContext *avctx){ |
|
|
|
static av_cold int png_enc_init(AVCodecContext *avctx) |
|
|
|
|
|
|
|
{ |
|
|
|
PNGEncContext *s = avctx->priv_data; |
|
|
|
PNGEncContext *s = avctx->priv_data; |
|
|
|
|
|
|
|
|
|
|
|
avctx->coded_frame = av_frame_alloc(); |
|
|
|
avctx->coded_frame = av_frame_alloc(); |
|
|
@ -448,7 +456,9 @@ static av_cold int png_enc_init(AVCodecContext *avctx){ |
|
|
|
|
|
|
|
|
|
|
|
ff_dsputil_init(&s->dsp, avctx); |
|
|
|
ff_dsputil_init(&s->dsp, avctx); |
|
|
|
|
|
|
|
|
|
|
|
s->filter_type = av_clip(avctx->prediction_method, PNG_FILTER_VALUE_NONE, PNG_FILTER_VALUE_MIXED); |
|
|
|
s->filter_type = av_clip(avctx->prediction_method, |
|
|
|
|
|
|
|
PNG_FILTER_VALUE_NONE, |
|
|
|
|
|
|
|
PNG_FILTER_VALUE_MIXED); |
|
|
|
if (avctx->pix_fmt == AV_PIX_FMT_MONOBLACK) |
|
|
|
if (avctx->pix_fmt == AV_PIX_FMT_MONOBLACK) |
|
|
|
s->filter_type = PNG_FILTER_VALUE_NONE; |
|
|
|
s->filter_type = PNG_FILTER_VALUE_NONE; |
|
|
|
|
|
|
|
|
|
|
|