[FFmpeg-devel] [PATCH 3/3] lavc/libopenjpegenc: add cinema_setup_encoder function to allow creation of dci compliant files

Jean First jeanfirst at gmail.com
Wed Jan 28 16:41:26 CET 2015


 code originates from image_to_j2k.c provided by openjpeg

Signed-off-by: Jean First <jeanfirst at gmail.com>
---
 libavcodec/libopenjpegenc.c | 118 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 118 insertions(+)

diff --git a/libavcodec/libopenjpegenc.c b/libavcodec/libopenjpegenc.c
index b9a8bac..8c8bf67 100644
--- a/libavcodec/libopenjpegenc.c
+++ b/libavcodec/libopenjpegenc.c
@@ -26,6 +26,11 @@
 
 #define  OPJ_STATIC
 
+#define CINEMA_24_CS 1302083 /* Codestream length for 24fps */
+#define CINEMA_48_CS 651041  /* Codestream length for 48fps */
+#define COMP_24_CS 1041666   /* Maximum size per color component for 2K & 4K @ 24fps */
+#define COMP_48_CS 520833    /* Maximum size per color component for 2K @ 48fps */
+
 #include "libavutil/avassert.h"
 #include "libavutil/common.h"
 #include "libavutil/imgutils.h"
@@ -75,6 +80,25 @@ static void info_callback(const char *msg, void *data)
     av_log(data, AV_LOG_DEBUG, "%s\n", msg);
 }
 
+static int initialise_4K_poc(opj_poc_t *POC, int numres)
+{
+    POC[0].tile    = 1;
+    POC[0].resno0  = 0;
+    POC[0].compno0 = 0;
+    POC[0].layno1  = 1;
+    POC[0].resno1  = numres - 1;
+    POC[0].compno1 = 3;
+    POC[0].prg1    = CPRL;
+    POC[1].tile    = 1;
+    POC[1].resno0  = numres - 1;
+    POC[1].compno0 = 0;
+    POC[1].layno1  = 1;
+    POC[1].resno1  = numres;
+    POC[1].compno1 = 3;
+    POC[1].prg1    = CPRL;
+    return 2;
+}
+
 static void cinema_parameters(opj_cparameters_t *p)
 {
     p->tile_size_on = 0;
@@ -110,8 +134,98 @@ static void cinema_parameters(opj_cparameters_t *p)
     p->irreversible = 1;
 }
 
+static void cinema_setup_encoder(AVCodecContext *avctx, opj_image_t *image)
+{
+    LibOpenJPEGContext *ctx = avctx->priv_data;
+    opj_cparameters_t *parameters = &ctx->enc_params;
+    int i;
+    float temp_rate;
+
+    switch (parameters->cp_cinema) {
+        case CINEMA2K_24:
+        case CINEMA2K_48:
+            if (parameters->numresolution > 6) {
+                parameters->numresolution = 6;
+            }
+            if (!((image->comps[0].w == 2048) || (image->comps[0].h == 1080))) {
+                av_log(avctx, AV_LOG_WARNING, "Image coordinates %d x %d is not 2K compliant.\nJPEG Digital Cinema Profile-3 "
+                        "(2K profile) compliance requires that at least one of coordinates match 2048 x 1080\n",
+                        image->comps[0].w, image->comps[0].h);
+                parameters->cp_rsiz = STD_RSIZ;
+            }
+            break;
+
+        case CINEMA4K_24:
+            if (parameters->numresolution < 1) {
+                parameters->numresolution = 1;
+            } else if (parameters->numresolution > 7) {
+                parameters->numresolution = 7;
+            }
+            if (!((image->comps[0].w == 4096) || (image->comps[0].h == 2160))) {
+                av_log(avctx, AV_LOG_WARNING, "Image coordinates %d x %d is not 4K compliant.\nJPEG Digital Cinema Profile-4"
+                        "(4K profile) compliance requires that at least one of coordinates match 4096 x 2160\n",
+                        image->comps[0].w, image->comps[0].h);
+                parameters->cp_rsiz = STD_RSIZ;
+            }
+            parameters->numpocs = initialise_4K_poc(parameters->POC, parameters->numresolution);
+            break;
+        case OFF:
+            /* do nothing */
+            break;
+    }
+
+    switch (parameters->cp_cinema) {
+        case CINEMA2K_24:
+        case CINEMA4K_24:
+            for (i = 0; i < parameters->tcp_numlayers; i++) {
+                temp_rate = 0;
+                if (ctx->tcp_rates[i] == 0) {
+                    parameters->tcp_rates[0] = ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)) /
+                                               (CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy);
+                } else {
+                    temp_rate = ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)) /
+                                (ctx->tcp_rates[i] * 8 * image->comps[0].dx * image->comps[0].dy);
+                    if (temp_rate > CINEMA_24_CS) {
+                        parameters->tcp_rates[i] = ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)) /
+                                                   (CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy);
+                    } else {
+                        parameters->tcp_rates[i] = ctx->tcp_rates[i];
+                    }
+                }
+            }
+            parameters->max_comp_size = COMP_24_CS;
+            break;
+
+        case CINEMA2K_48:
+            for (i = 0; i < parameters->tcp_numlayers; i++) {
+                temp_rate = 0;
+                if (ctx->tcp_rates[i] == 0) {
+                    parameters->tcp_rates[0] = ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)) /
+                                               (CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy);
+                }
+                else {
+                    temp_rate = ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)) /
+                                (ctx->tcp_rates[i] * 8 * image->comps[0].dx * image->comps[0].dy);
+                    if (temp_rate > CINEMA_48_CS) {
+                        parameters->tcp_rates[0] = ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec)) /
+                                                   (CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy);
+                    } else {
+                        parameters->tcp_rates[i] = ctx->tcp_rates[i];
+                    }
+                }
+            }
+            parameters->max_comp_size = COMP_48_CS;
+            break;
+        case OFF:
+            /* do nothing */
+            break;
+    }
+    parameters->cp_disto_alloc = 1;
+}
+
 static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *parameters)
 {
+    LibOpenJPEGContext *ctx = avctx->priv_data;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
     opj_image_cmptparm_t cmptparm[4] = {{0}};
     opj_image_t *img;
@@ -208,6 +322,10 @@ static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *p
     img->x1 = (avctx->width  - 1) * parameters->subsampling_dx + 1;
     img->y1 = (avctx->height - 1) * parameters->subsampling_dy + 1;
 
+    if (ctx->cinema_mode > 0) {
+        cinema_setup_encoder(avctx, img);
+    }
+
     return img;
 }
 
-- 
2.2.2



More information about the ffmpeg-devel mailing list