]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/proresenc_kostya.c
avcodec: Constify AVCodecs
[ffmpeg] / libavcodec / proresenc_kostya.c
index 149dc81b3c79937bd7e737f29fd69150e46a1375..d140ef053ab5475a59bc3db1188a7b8d00013773 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/mem_internal.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avcodec.h"
 #include "fdctdsp.h"
 #include "put_bits.h"
+#include "profiles.h"
 #include "bytestream.h"
 #include "internal.h"
 #include "proresdata.h"
@@ -51,9 +53,11 @@ enum {
 
 enum {
     QUANT_MAT_PROXY = 0,
+    QUANT_MAT_PROXY_CHROMA,
     QUANT_MAT_LT,
     QUANT_MAT_STANDARD,
     QUANT_MAT_HQ,
+    QUANT_MAT_XQ_LUMA,
     QUANT_MAT_DEFAULT,
 };
 
@@ -68,6 +72,16 @@ static const uint8_t prores_quant_matrices[][64] = {
         13, 63, 63, 63, 63, 63, 63, 63,
         63, 63, 63, 63, 63, 63, 63, 63,
     },
+    { // proxy chromas
+        4,  7,  9, 11, 13, 14, 63, 63,
+        7,  7, 11, 12, 14, 63, 63, 63,
+        9, 11, 13, 14, 63, 63, 63, 63,
+        11, 11, 13, 14, 63, 63, 63, 63,
+        11, 13, 14, 63, 63, 63, 63, 63,
+        13, 14, 63, 63, 63, 63, 63, 63,
+        13, 63, 63, 63, 63, 63, 63, 63,
+        63, 63, 63, 63, 63, 63, 63, 63
+    },
     { // LT
          4,  5,  6,  7,  9, 11, 13, 15,
          5,  5,  7,  8, 11, 13, 15, 17,
@@ -98,6 +112,16 @@ static const uint8_t prores_quant_matrices[][64] = {
          4,  4,  4,  4,  5,  5,  6,  7,
          4,  4,  4,  4,  5,  6,  7,  7,
     },
+    { // XQ luma
+        2,  2,  2,  2,  2,  2,  2,  2,
+        2,  2,  2,  2,  2,  2,  2,  2,
+        2,  2,  2,  2,  2,  2,  2,  2,
+        2,  2,  2,  2,  2,  2,  2,  3,
+        2,  2,  2,  2,  2,  2,  3,  3,
+        2,  2,  2,  2,  2,  3,  3,  3,
+        2,  2,  2,  2,  3,  3,  3,  4,
+        2,  2,  2,  2,  3,  3,  4,  4,
+    },
     { // codec default
          4,  4,  4,  4,  4,  4,  4,  4,
          4,  4,  4,  4,  4,  4,  4,  4,
@@ -125,6 +149,7 @@ static const struct prores_profile {
     int         max_quant;
     int         br_tab[NUM_MB_LIMITS];
     int         quant;
+    int         quant_chroma;
 } prores_profile_info[6] = {
     {
         .full_name = "proxy",
@@ -133,6 +158,7 @@ static const struct prores_profile {
         .max_quant = 8,
         .br_tab    = { 300, 242, 220, 194 },
         .quant     = QUANT_MAT_PROXY,
+        .quant_chroma = QUANT_MAT_PROXY_CHROMA,
     },
     {
         .full_name = "LT",
@@ -141,6 +167,7 @@ static const struct prores_profile {
         .max_quant = 9,
         .br_tab    = { 720, 560, 490, 440 },
         .quant     = QUANT_MAT_LT,
+        .quant_chroma = QUANT_MAT_LT,
     },
     {
         .full_name = "standard",
@@ -149,6 +176,7 @@ static const struct prores_profile {
         .max_quant = 6,
         .br_tab    = { 1050, 808, 710, 632 },
         .quant     = QUANT_MAT_STANDARD,
+        .quant_chroma = QUANT_MAT_STANDARD,
     },
     {
         .full_name = "high quality",
@@ -157,6 +185,7 @@ static const struct prores_profile {
         .max_quant = 6,
         .br_tab    = { 1566, 1216, 1070, 950 },
         .quant     = QUANT_MAT_HQ,
+        .quant_chroma = QUANT_MAT_HQ,
     },
     {
         .full_name = "4444",
@@ -165,6 +194,7 @@ static const struct prores_profile {
         .max_quant = 6,
         .br_tab    = { 2350, 1828, 1600, 1425 },
         .quant     = QUANT_MAT_HQ,
+        .quant_chroma = QUANT_MAT_HQ,
     },
     {
         .full_name = "4444XQ",
@@ -172,7 +202,8 @@ static const struct prores_profile {
         .min_quant = 1,
         .max_quant = 6,
         .br_tab    = { 3525, 2742, 2400, 2137 },
-        .quant     = QUANT_MAT_HQ,
+        .quant     = QUANT_MAT_HQ, /* Fix me : use QUANT_MAT_XQ_LUMA */
+        .quant_chroma = QUANT_MAT_HQ,
     }
 };
 
@@ -192,6 +223,7 @@ typedef struct ProresThreadData {
     DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
     DECLARE_ALIGNED(16, uint16_t, emu_buf)[16 * 16];
     int16_t custom_q[64];
+    int16_t custom_chroma_q[64];
     struct TrellisNode *nodes;
 } ProresThreadData;
 
@@ -200,8 +232,11 @@ typedef struct ProresContext {
     DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
     DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16];
     int16_t quants[MAX_STORED_Q][64];
+    int16_t quants_chroma[MAX_STORED_Q][64];
     int16_t custom_q[64];
+    int16_t custom_chroma_q[64];
     const uint8_t *quant_mat;
+    const uint8_t *quant_chroma_mat;
     const uint8_t *scantable;
 
     void (*fdct)(FDCTDSPContext *fdsp, const uint16_t *src,
@@ -429,23 +464,17 @@ static void encode_acs(PutBitContext *pb, int16_t *blocks,
     }
 }
 
-static int encode_slice_plane(ProresContext *ctx, PutBitContext *pb,
+static void encode_slice_plane(ProresContext *ctx, PutBitContext *pb,
                               const uint16_t *src, ptrdiff_t linesize,
                               int mbs_per_slice, int16_t *blocks,
                               int blocks_per_mb, int plane_size_factor,
                               const int16_t *qmat)
 {
-    int blocks_per_slice, saved_pos;
-
-    saved_pos = put_bits_count(pb);
-    blocks_per_slice = mbs_per_slice * blocks_per_mb;
+    int blocks_per_slice = mbs_per_slice * blocks_per_mb;
 
     encode_dcs(pb, blocks, blocks_per_slice, qmat[0]);
     encode_acs(pb, blocks, blocks_per_slice, plane_size_factor,
                ctx->scantable, qmat);
-    flush_put_bits(pb);
-
-    return (put_bits_count(pb) - saved_pos) >> 3;
 }
 
 static void put_alpha_diff(PutBitContext *pb, int cur, int prev, int abits)
@@ -481,14 +510,13 @@ static void put_alpha_run(PutBitContext *pb, int run)
 }
 
 // todo alpha quantisation for high quants
-static int encode_alpha_plane(ProresContext *ctx, PutBitContext *pb,
+static void encode_alpha_plane(ProresContext *ctx, PutBitContext *pb,
                               int mbs_per_slice, uint16_t *blocks,
                               int quant)
 {
     const int abits = ctx->alpha_bits;
     const int mask  = (1 << abits) - 1;
     const int num_coeffs = mbs_per_slice * 256;
-    int saved_pos = put_bits_count(pb);
     int prev = mask, cur;
     int idx = 0;
     int run = 0;
@@ -509,8 +537,6 @@ static int encode_alpha_plane(ProresContext *ctx, PutBitContext *pb,
     } while (idx < num_coeffs);
     if (run)
         put_alpha_run(pb, run);
-    flush_put_bits(pb);
-    return (put_bits_count(pb) - saved_pos) >> 3;
 }
 
 static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
@@ -527,6 +553,7 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
     ptrdiff_t linesize;
     int plane_factor, is_chroma;
     uint16_t *qmat;
+    uint16_t *qmat_chroma;
 
     if (ctx->pictures_per_frame == 1)
         line_add = 0;
@@ -535,12 +562,17 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
 
     if (ctx->force_quant) {
         qmat = ctx->quants[0];
+        qmat_chroma = ctx->quants_chroma[0];
     } else if (quant < MAX_STORED_Q) {
         qmat = ctx->quants[quant];
+        qmat_chroma = ctx->quants_chroma[quant];
     } else {
         qmat = ctx->custom_q;
-        for (i = 0; i < 64; i++)
+        qmat_chroma = ctx->custom_chroma_q;
+        for (i = 0; i < 64; i++) {
             qmat[i] = ctx->quant_mat[i] * quant;
+            qmat_chroma[i] = ctx->quant_chroma_mat[i] * quant;
+        }
     }
 
     for (i = 0; i < ctx->num_planes; i++) {
@@ -569,23 +601,24 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
                            pwidth, avctx->height / ctx->pictures_per_frame,
                            ctx->blocks[0], ctx->emu_buf,
                            mbs_per_slice, num_cblocks, is_chroma);
-            sizes[i] = encode_slice_plane(ctx, pb, src, linesize,
-                                          mbs_per_slice, ctx->blocks[0],
-                                          num_cblocks, plane_factor,
-                                          qmat);
+            if (!is_chroma) {/* luma quant */
+                encode_slice_plane(ctx, pb, src, linesize,
+                                   mbs_per_slice, ctx->blocks[0],
+                                   num_cblocks, plane_factor, qmat);
+            } else { /* chroma plane */
+                encode_slice_plane(ctx, pb, src, linesize,
+                                   mbs_per_slice, ctx->blocks[0],
+                                   num_cblocks, plane_factor, qmat_chroma);
+            }
         } else {
             get_alpha_data(ctx, src, linesize, xp, yp,
                            pwidth, avctx->height / ctx->pictures_per_frame,
                            ctx->blocks[0], mbs_per_slice, ctx->alpha_bits);
-            sizes[i] = encode_alpha_plane(ctx, pb, mbs_per_slice,
-                                          ctx->blocks[0], quant);
-        }
-        total_size += sizes[i];
-        if (put_bits_left(pb) < 0) {
-            av_log(avctx, AV_LOG_ERROR,
-                   "Underestimated required buffer size.\n");
-            return AVERROR_BUG;
+            encode_alpha_plane(ctx, pb, mbs_per_slice, ctx->blocks[0], quant);
         }
+        flush_put_bits(pb);
+        sizes[i]   = put_bytes_output(pb) - total_size;
+        total_size = put_bytes_output(pb);
     }
     return total_size;
 }
@@ -712,10 +745,9 @@ static int est_alpha_diff(int cur, int prev, int abits)
         return dbits + 1;
 }
 
-static int estimate_alpha_plane(ProresContext *ctx, int *error,
+static int estimate_alpha_plane(ProresContext *ctx,
                                 const uint16_t *src, ptrdiff_t linesize,
-                                int mbs_per_slice, int quant,
-                                int16_t *blocks)
+                                int mbs_per_slice, int16_t *blocks)
 {
     const int abits = ctx->alpha_bits;
     const int mask  = (1 << abits) - 1;
@@ -725,7 +757,6 @@ static int estimate_alpha_plane(ProresContext *ctx, int *error,
     int run = 0;
     int bits;
 
-    *error = 0;
     cur = blocks[idx++];
     bits = est_alpha_diff(cur, prev, abits);
     prev = cur;
@@ -773,7 +804,9 @@ static int find_slice_quant(AVCodecContext *avctx,
     int slice_bits[TRELLIS_WIDTH], slice_score[TRELLIS_WIDTH];
     int overquant;
     uint16_t *qmat;
+    uint16_t *qmat_chroma;
     int linesize[4], line_add;
+    int alpha_bits = 0;
 
     if (ctx->pictures_per_frame == 1)
         line_add = 0;
@@ -819,20 +852,25 @@ static int find_slice_quant(AVCodecContext *avctx,
         td->nodes[trellis_node + q].quant     = q;
     }
 
+    if (ctx->alpha_bits)
+        alpha_bits = estimate_alpha_plane(ctx, src, linesize[3],
+                                          mbs_per_slice, td->blocks[3]);
     // todo: maybe perform coarser quantising to fit into frame size when needed
     for (q = min_quant; q <= max_quant; q++) {
-        bits  = 0;
+        bits  = alpha_bits;
         error = 0;
-        for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
+        bits += estimate_slice_plane(ctx, &error, 0,
+                                     src, linesize[0],
+                                     mbs_per_slice,
+                                     num_cblocks[0], plane_factor[0],
+                                     ctx->quants[q], td); /* estimate luma plane */
+        for (i = 1; i < ctx->num_planes - !!ctx->alpha_bits; i++) { /* estimate chroma plane */
             bits += estimate_slice_plane(ctx, &error, i,
                                          src, linesize[i],
                                          mbs_per_slice,
                                          num_cblocks[i], plane_factor[i],
-                                         ctx->quants[q], td);
+                                         ctx->quants_chroma[q], td);
         }
-        if (ctx->alpha_bits)
-            bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
-                                         mbs_per_slice, q, td->blocks[3]);
         if (bits > 65000 * 8)
             error = SCORE_LIMIT;
 
@@ -845,25 +883,31 @@ static int find_slice_quant(AVCodecContext *avctx,
         overquant = max_quant;
     } else {
         for (q = max_quant + 1; q < 128; q++) {
-            bits  = 0;
+            bits  = alpha_bits;
             error = 0;
             if (q < MAX_STORED_Q) {
                 qmat = ctx->quants[q];
+                qmat_chroma = ctx->quants_chroma[q];
             } else {
                 qmat = td->custom_q;
-                for (i = 0; i < 64; i++)
+                qmat_chroma = td->custom_chroma_q;
+                for (i = 0; i < 64; i++) {
                     qmat[i] = ctx->quant_mat[i] * q;
+                    qmat_chroma[i] = ctx->quant_chroma_mat[i] * q;
+                }
             }
-            for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
+            bits += estimate_slice_plane(ctx, &error, 0,
+                                         src, linesize[0],
+                                         mbs_per_slice,
+                                         num_cblocks[0], plane_factor[0],
+                                         qmat, td);/* estimate luma plane */
+            for (i = 1; i < ctx->num_planes - !!ctx->alpha_bits; i++) { /* estimate chroma plane */
                 bits += estimate_slice_plane(ctx, &error, i,
                                              src, linesize[i],
                                              mbs_per_slice,
                                              num_cblocks[i], plane_factor[i],
-                                             qmat, td);
+                                             qmat_chroma, td);
             }
-            if (ctx->alpha_bits)
-                bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
-                                             mbs_per_slice, q, td->blocks[3]);
             if (bits <= ctx->bits_per_mb * mbs_per_slice)
                 break;
         }
@@ -1135,12 +1179,6 @@ static av_cold int encode_init(AVCodecContext *avctx)
     int interlaced = !!(avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT);
 
     avctx->bits_per_raw_sample = 10;
-#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
 
     ctx->fdct      = prores_fdct;
     ctx->scantable = interlaced ? ff_prores_interlaced_scan
@@ -1198,10 +1236,13 @@ FF_ENABLE_DEPRECATION_WARNINGS
     ctx->slices_per_picture = ctx->mb_height * ctx->slices_width;
     ctx->pictures_per_frame = 1 + interlaced;
 
-    if (ctx->quant_sel == -1)
+    if (ctx->quant_sel == -1) {
         ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant];
-    else
+        ctx->quant_chroma_mat = prores_quant_matrices[ctx->profile_info->quant_chroma];
+    } else {
         ctx->quant_mat = prores_quant_matrices[ctx->quant_sel];
+        ctx->quant_chroma_mat = prores_quant_matrices[ctx->quant_sel];
+    }
 
     if (strlen(ctx->vendor) != 4) {
         av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n");
@@ -1226,8 +1267,10 @@ FF_ENABLE_DEPRECATION_WARNINGS
         min_quant = ctx->profile_info->min_quant;
         max_quant = ctx->profile_info->max_quant;
         for (i = min_quant; i < MAX_STORED_Q; i++) {
-            for (j = 0; j < 64; j++)
+            for (j = 0; j < 64; j++) {
                 ctx->quants[i][j] = ctx->quant_mat[j] * i;
+                ctx->quants_chroma[i][j] = ctx->quant_chroma_mat[j] * i;
+            }
         }
 
         ctx->slice_q = av_malloc(ctx->slices_per_picture * sizeof(*ctx->slice_q));
@@ -1258,6 +1301,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
         }
     } else {
         int ls = 0;
+        int ls_chroma = 0;
 
         if (ctx->force_quant > 64) {
             av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is 64\n");
@@ -1266,12 +1310,14 @@ FF_ENABLE_DEPRECATION_WARNINGS
 
         for (j = 0; j < 64; j++) {
             ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant;
+            ctx->quants_chroma[0][j] = ctx->quant_chroma_mat[j] * ctx->force_quant;
             ls += av_log2((1 << 11)  / ctx->quants[0][j]) * 2 + 1;
+            ls_chroma += av_log2((1 << 11)  / ctx->quants_chroma[0][j]) * 2 + 1;
         }
 
-        ctx->bits_per_mb = ls * 8;
+        ctx->bits_per_mb = ls * 4 + ls_chroma * 4;
         if (ctx->chroma_factor == CFACTOR_Y444)
-            ctx->bits_per_mb += ls * 4;
+            ctx->bits_per_mb += ls_chroma * 4;
     }
 
     ctx->frame_size_upper_bound = (ctx->pictures_per_frame *
@@ -1324,7 +1370,7 @@ static const AVOption options[] = {
     { "4444xq",        NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_4444XQ },
         0, 0, VE, "profile" },
     { "vendor", "vendor ID", OFFSET(vendor),
-        AV_OPT_TYPE_STRING, { .str = "Lavc" }, CHAR_MIN, CHAR_MAX, VE },
+        AV_OPT_TYPE_STRING, { .str = "Lavc" }, 0, 0, VE },
     { "bits_per_mb", "desired bits per macroblock", OFFSET(bits_per_mb),
         AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 8192, VE },
     { "quant_mat", "quantiser matrix", OFFSET(quant_sel), AV_OPT_TYPE_INT,
@@ -1353,7 +1399,7 @@ static const AVClass proresenc_class = {
     .version    = LIBAVUTIL_VERSION_INT,
 };
 
-AVCodec ff_prores_ks_encoder = {
+const AVCodec ff_prores_ks_encoder = {
     .name           = "prores_ks",
     .long_name      = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"),
     .type           = AVMEDIA_TYPE_VIDEO,
@@ -1362,10 +1408,11 @@ AVCodec ff_prores_ks_encoder = {
     .init           = encode_init,
     .close          = encode_close,
     .encode2        = encode_frame,
-    .capabilities   = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY,
+    .capabilities   = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS,
     .pix_fmts       = (const enum AVPixelFormat[]) {
                           AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
                           AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE
                       },
     .priv_class     = &proresenc_class,
+    .profiles       = NULL_IF_CONFIG_SMALL(ff_prores_profiles),
 };