X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=libavcodec%2Fpngenc.c;h=f91c54c7deda6ed9d2c2e5c3654a1a01d76d835d;hb=3df77b58e35a30ed550f99936a308f6bd2f47a20;hp=ccc5f7dada7235ea31f7abc9f7b803999df1b745;hpb=c598b569fb3d1f4b6c4868fe64f6989254df5186;p=ffmpeg diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c index ccc5f7dada7..f91c54c7ded 100644 --- a/libavcodec/pngenc.c +++ b/libavcodec/pngenc.c @@ -19,9 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/opt.h" +#include "libavutil/stereo3d.h" + #include "avcodec.h" #include "bytestream.h" -#include "dsputil.h" +#include "huffyuvencdsp.h" #include "png.h" /* TODO: @@ -33,7 +36,8 @@ #define IOBUF_SIZE 4096 typedef struct PNGEncContext { - DSPContext dsp; + AVClass *class; + HuffYUVEncDSPContext hdsp; uint8_t *bytestream; uint8_t *bytestream_start; @@ -111,7 +115,7 @@ static void sub_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, } } -static void png_filter_row(DSPContext *dsp, uint8_t *dst, int filter_type, +static void png_filter_row(PNGEncContext *c, uint8_t *dst, int filter_type, uint8_t *src, uint8_t *top, int size, int bpp) { int i; @@ -121,11 +125,11 @@ static void png_filter_row(DSPContext *dsp, uint8_t *dst, int filter_type, memcpy(dst, src, size); break; case PNG_FILTER_VALUE_SUB: - dsp->diff_bytes(dst, src, src - bpp, size); + c->hdsp.diff_bytes(dst, src, src - bpp, size); memcpy(dst, src, bpp); break; case PNG_FILTER_VALUE_UP: - dsp->diff_bytes(dst, src, top, size); + c->hdsp.diff_bytes(dst, src, top, size); break; case PNG_FILTER_VALUE_AVG: for (i = 0; i < bpp; i++) @@ -153,7 +157,7 @@ static uint8_t *png_choose_filter(PNGEncContext *s, uint8_t *dst, int cost, bcost = INT_MAX; uint8_t *buf1 = dst, *buf2 = dst + size + 16; for (pred = 0; pred < 5; pred++) { - png_filter_row(&s->dsp, buf1 + 1, pred, src, top, size, bpp); + png_filter_row(s, buf1 + 1, pred, src, top, size, bpp); buf1[0] = pred; cost = 0; for (i = 0; i <= size; i++) @@ -165,7 +169,7 @@ static uint8_t *png_choose_filter(PNGEncContext *s, uint8_t *dst, } return buf2; } else { - png_filter_row(&s->dsp, dst + 1, pred, src, top, size, bpp); + png_filter_row(s, dst + 1, pred, src, top, size, bpp); dst[0] = pred; return dst; } @@ -213,7 +217,7 @@ static int png_write_row(PNGEncContext *s, const uint8_t *data, int size) int ret; s->zstream.avail_in = size; - s->zstream.next_in = (uint8_t *)data; + s->zstream.next_in = data; while (s->zstream.avail_in > 0) { ret = deflate(&s->zstream, Z_NO_FLUSH); if (ret != Z_OK) @@ -233,6 +237,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet) { PNGEncContext *s = avctx->priv_data; + AVFrameSideData *side_data; const AVFrame *const p = pict; 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; @@ -243,8 +248,16 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, uint8_t *rgba_buf = NULL; uint8_t *top_buf = NULL; - is_progressive = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT); + is_progressive = !!(avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT); switch (avctx->pix_fmt) { + case AV_PIX_FMT_RGBA64BE: + bit_depth = 16; + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + break; + case AV_PIX_FMT_RGB48BE: + bit_depth = 16; + color_type = PNG_COLOR_TYPE_RGB; + break; case AV_PIX_FMT_RGB32: bit_depth = 8; color_type = PNG_COLOR_TYPE_RGB_ALPHA; @@ -289,7 +302,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, enc_row_size = deflateBound(&s->zstream, row_size); max_packet_size = avctx->height * (enc_row_size + ((enc_row_size + IOBUF_SIZE - 1) / IOBUF_SIZE) * 12) - + FF_MIN_BUFFER_SIZE; + + AV_INPUT_BUFFER_MIN_SIZE; if (!pkt->data && (ret = av_new_packet(pkt, max_packet_size)) < 0) { av_log(avctx, AV_LOG_ERROR, "Could not allocate output packet of size %d.\n", @@ -363,6 +376,25 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, } } + /* write stereoscopic information */ + side_data = av_frame_get_side_data(pict, AV_FRAME_DATA_STEREO3D); + if (side_data) { + AVStereo3D *stereo3d = (AVStereo3D *)side_data->data; + uint8_t sm; + switch (stereo3d->type) { + case AV_STEREO3D_SIDEBYSIDE: + sm = !(stereo3d->flags & AV_STEREO3D_FLAG_INVERT); + png_write_chunk(&s->bytestream, MKTAG('s', 'T', 'E', 'R'), &sm, 1); + break; + case AV_STEREO3D_2D: + break; + default: + av_log(avctx, AV_LOG_WARNING, + "Only side-by-side stereo3d flag can be defined within sTER chunk\n"); + break; + } + } + /* now put each row */ s->zstream.avail_out = IOBUF_SIZE; s->zstream.next_out = s->buf; @@ -447,42 +479,62 @@ static av_cold int png_enc_init(AVCodecContext *avctx) { PNGEncContext *s = avctx->priv_data; - avctx->coded_frame = av_frame_alloc(); - if (!avctx->coded_frame) - return AVERROR(ENOMEM); - +#if FF_API_CODED_FRAME +FF_DISABLE_DEPRECATION_WARNINGS avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I; avctx->coded_frame->key_frame = 1; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + ff_huffyuvencdsp_init(&s->hdsp); - ff_dsputil_init(&s->dsp, avctx); +#if FF_API_PRIVATE_OPT +FF_DISABLE_DEPRECATION_WARNINGS + if (avctx->prediction_method) + s->filter_type = av_clip(avctx->prediction_method, + PNG_FILTER_VALUE_NONE, + PNG_FILTER_VALUE_MIXED); +FF_ENABLE_DEPRECATION_WARNINGS +#endif - s->filter_type = av_clip(avctx->prediction_method, - PNG_FILTER_VALUE_NONE, - PNG_FILTER_VALUE_MIXED); if (avctx->pix_fmt == AV_PIX_FMT_MONOBLACK) s->filter_type = PNG_FILTER_VALUE_NONE; return 0; } -static av_cold int png_enc_close(AVCodecContext *avctx) -{ - av_frame_free(&avctx->coded_frame); - return 0; -} +#define OFFSET(x) offsetof(PNGEncContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { +{ "pred", "Prediction method", OFFSET(filter_type), AV_OPT_TYPE_INT, { .i64 = PNG_FILTER_VALUE_NONE }, PNG_FILTER_VALUE_NONE, PNG_FILTER_VALUE_MIXED, VE, "pred" }, + { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_NONE }, INT_MIN, INT_MAX, VE, "pred" }, + { "sub", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_SUB }, INT_MIN, INT_MAX, VE, "pred" }, + { "up", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_UP }, INT_MIN, INT_MAX, VE, "pred" }, + { "avg", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_AVG }, INT_MIN, INT_MAX, VE, "pred" }, + { "paeth", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_PAETH }, INT_MIN, INT_MAX, VE, "pred" }, + { "mixed", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_MIXED }, INT_MIN, INT_MAX, VE, "pred" }, + + { NULL}, +}; +static const AVClass png_class = { + .class_name = "png", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; AVCodec ff_png_encoder = { .name = "png", .long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_PNG, .priv_data_size = sizeof(PNGEncContext), + .priv_class = &png_class, .init = png_enc_init, - .close = png_enc_close, .encode2 = encode_frame, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB32, AV_PIX_FMT_PAL8, AV_PIX_FMT_GRAY8, - AV_PIX_FMT_GRAY16BE, + AV_PIX_FMT_RGBA64BE, AV_PIX_FMT_RGB48BE, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE }, };