]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/pngenc.c
nvenc: Allow different const qps for I, P and B frames
[ffmpeg] / libavcodec / pngenc.c
index ccc5f7dada7235ea31f7abc9f7b803999df1b745..f91c54c7deda6ed9d2c2e5c3654a1a01d76d835d 100644 (file)
  * 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
     },
 };