Subject: [PATCH] Add jpeg2000 subdescriptor (take into account FFmpeg community remarks).
From: Cedric Le Barz <[email-masked]>
To: [email-masked]
Date: Wed, 5 Apr 2023 11:59:18 +0200

Signed-off-by: Cedric Le Barz <[email-masked]>
---
 ffmpeg/libavcodec/j2kenc.c      |  28 +++---
 ffmpeg/libavcodec/jpeg2000.h    |  90 +++++++++++++++++
 ffmpeg/libavcodec/jpeg2000dec.c |  89 +----------------
 ffmpeg/libavformat/mxf.h        |   1 +
 ffmpeg/libavformat/mxfenc.c     | 169 +++++++++++++++++++++++++++++++-
 5 files changed, 273 insertions(+), 104 deletions(-)

diff --git a/ffmpeg/libavcodec/j2kenc.c b/ffmpeg/libavcodec/j2kenc.c
index 6406f90..f5178d7 100644
--- a/ffmpeg/libavcodec/j2kenc.c
+++ b/ffmpeg/libavcodec/j2kenc.c
@@ -106,7 +106,7 @@ static const int dwt_norms[2][4][10] = { // [dwt_type][band][rlevel] (multiplied
 typedef struct {
    Jpeg2000Component *comp;
    double *layer_rates;
-} Jpeg2000Tile;
+} J2kTile;
 
 typedef struct {
     AVClass *class;
@@ -131,7 +131,7 @@ typedef struct {
     Jpeg2000CodingStyle codsty;
     Jpeg2000QuantStyle  qntsty;
 
-    Jpeg2000Tile *tile;
+    J2kTile *tile;
     int layer_rates[100];
     uint8_t compression_rate_enc; ///< Is compression done using compression ratio?
 
@@ -171,7 +171,7 @@ static void dump(Jpeg2000EncoderContext *s, FILE *fd)
             s->width, s->height, s->tile_width, s->tile_height,
             s->numXtiles, s->numYtiles, s->ncomponents);
     for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
-        Jpeg2000Tile *tile = s->tile + tileno;
+        J2kTile *tile = s->tile + tileno;
         nspaces(fd, 2);
         fprintf(fd, "tile %d:\n", tileno);
         for(compno = 0; compno < s->ncomponents; compno++){
@@ -427,7 +427,7 @@ static void compute_rates(Jpeg2000EncoderContext* s)
     int layno, compno;
     for (i = 0; i < s->numYtiles; i++) {
         for (j = 0; j < s->numXtiles; j++) {
-            Jpeg2000Tile *tile = &s->tile[s->numXtiles * i + j];
+            J2kTile *tile = &s->tile[s->numXtiles * i + j];
             for (compno = 0; compno < s->ncomponents; compno++) {
                 int tilew = tile->comp[compno].coord[0][1] - tile->comp[compno].coord[0][0];
                 int tileh = tile->comp[compno].coord[1][1] - tile->comp[compno].coord[1][0];
@@ -460,12 +460,12 @@ static int init_tiles(Jpeg2000EncoderContext *s)
     s->numXtiles = ff_jpeg2000_ceildiv(s->width, s->tile_width);
     s->numYtiles = ff_jpeg2000_ceildiv(s->height, s->tile_height);
 
-    s->tile = av_calloc(s->numXtiles, s->numYtiles * sizeof(Jpeg2000Tile));
+    s->tile = av_calloc(s->numXtiles, s->numYtiles * sizeof(J2kTile));
     if (!s->tile)
         return AVERROR(ENOMEM);
     for (tileno = 0, tiley = 0; tiley < s->numYtiles; tiley++)
         for (tilex = 0; tilex < s->numXtiles; tilex++, tileno++){
-            Jpeg2000Tile *tile = s->tile + tileno;
+            J2kTile *tile = s->tile + tileno;
 
             tile->comp = av_calloc(s->ncomponents, sizeof(*tile->comp));
             if (!tile->comp)
@@ -509,7 +509,7 @@ static int init_tiles(Jpeg2000EncoderContext *s)
         int tileno, compno, i, y, x;                                                                                        \
         const PIXEL *line;                                                                                                  \
         for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){                                                   \
-            Jpeg2000Tile *tile = s->tile + tileno;                                                                          \
+            J2kTile *tile = s->tile + tileno;                                                                          \
             if (s->planar){                                                                                                 \
                 for (compno = 0; compno < s->ncomponents; compno++){                                                        \
                     Jpeg2000Component *comp = tile->comp + compno;                                                          \
@@ -701,7 +701,7 @@ static void encode_clnpass(Jpeg2000T1Context *t1, int width, int height, int ban
         }
 }
 
-static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, Jpeg2000Tile *tile,
+static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, J2kTile *tile,
                         int width, int height, int bandpos, int lev)
 {
     int pass_t = 2, passno, x, y, max=0, nmsedec, bpno;
@@ -935,7 +935,7 @@ static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, in
     return 0;
 }
 
-static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno, int nlayers)
+static int encode_packets(Jpeg2000EncoderContext *s, J2kTile *tile, int tileno, int nlayers)
 {
     int compno, reslevelno, layno, ret;
     Jpeg2000CodingStyle *codsty = &s->codsty;
@@ -1181,7 +1181,7 @@ static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int til
     return 0;
 }
 
-static void makelayer(Jpeg2000EncoderContext *s, int layno, double thresh, Jpeg2000Tile* tile, int final)
+static void makelayer(Jpeg2000EncoderContext *s, int layno, double thresh, J2kTile* tile, int final)
 {
     int compno, resno, bandno, precno, cblkno;
     int passno;
@@ -1264,7 +1264,7 @@ static void makelayer(Jpeg2000EncoderContext *s, int layno, double thresh, Jpeg2
     }
 }
 
-static void makelayers(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile)
+static void makelayers(Jpeg2000EncoderContext *s, J2kTile *tile)
 {
     int precno, compno, reslevelno, bandno, cblkno, lev, passno, layno;
     int i;
@@ -1365,7 +1365,7 @@ static int getcut(Jpeg2000Cblk *cblk, int64_t lambda, int dwt_norm)
     return res;
 }
 
-static void truncpasses(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile)
+static void truncpasses(Jpeg2000EncoderContext *s, J2kTile *tile)
 {
     int precno, compno, reslevelno, bandno, cblkno, lev;
     Jpeg2000CodingStyle *codsty = &s->codsty;
@@ -1399,7 +1399,7 @@ static void truncpasses(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile)
     }
 }
 
-static int encode_tile(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno)
+static int encode_tile(Jpeg2000EncoderContext *s, J2kTile *tile, int tileno)
 {
     int compno, reslevelno, bandno, ret;
     Jpeg2000T1Context t1;
@@ -1514,7 +1514,7 @@ static void reinit(Jpeg2000EncoderContext *s)
 {
     int tileno, compno;
     for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
-        Jpeg2000Tile *tile = s->tile + tileno;
+        J2kTile *tile = s->tile + tileno;
         for (compno = 0; compno < s->ncomponents; compno++)
             ff_jpeg2000_reinit(tile->comp + compno, &s->codsty);
     }
diff --git a/ffmpeg/libavcodec/jpeg2000.h b/ffmpeg/libavcodec/jpeg2000.h
index e5ecb4c..e1ebca5 100644
--- a/ffmpeg/libavcodec/jpeg2000.h
+++ b/ffmpeg/libavcodec/jpeg2000.h
@@ -33,7 +33,9 @@
 
 #include "avcodec.h"
 #include "mqc.h"
+#include "bytestream.h"
 #include "jpeg2000dwt.h"
+#include "jpeg2000dsp.h"
 
 enum Jpeg2000Markers {
     JPEG2000_SOC = 0xff4f, // start of codestream
@@ -120,6 +122,8 @@ enum Jpeg2000Quantsty { // quantization style
 #define JPEG2000_PGOD_PCRL      0x03  // Position-component-resolution level-layer progression
 #define JPEG2000_PGOD_CPRL      0x04  // Component-position-resolution level-layer progression
 
+#define MAX_POCS 32
+
 typedef struct Jpeg2000T1Context {
     int data[6144];
     uint16_t flags[6156];
@@ -227,6 +231,90 @@ typedef struct Jpeg2000Component {
     uint8_t roi_shift; // ROI scaling value for the component
 } Jpeg2000Component;
 
+
+typedef struct Jpeg2000POCEntry {
+    uint16_t LYEpoc;
+    uint16_t CSpoc;
+    uint16_t CEpoc;
+    uint8_t RSpoc;
+    uint8_t REpoc;
+    uint8_t Ppoc;
+} Jpeg2000POCEntry;
+
+typedef struct Jpeg2000POC {
+    Jpeg2000POCEntry poc[MAX_POCS];
+    int nb_poc;
+    int is_default;
+} Jpeg2000POC;
+
+typedef struct Jpeg2000TilePart {
+    uint8_t tile_index;                 // Tile index who refers the tile-part
+    const uint8_t *tp_end;
+    GetByteContext header_tpg;          // bit stream of header if PPM header is used
+    GetByteContext tpg;                 // bit stream in tile-part
+} Jpeg2000TilePart;
+
+typedef struct Jpeg2000Tile {
+    Jpeg2000Component   *comp;
+    uint8_t             properties[4];
+    Jpeg2000CodingStyle codsty[4];
+    Jpeg2000QuantStyle  qntsty[4];
+    Jpeg2000POC         poc;
+    Jpeg2000TilePart    tile_part[32];
+    uint8_t             has_ppt;                // whether this tile has a ppt marker
+    uint8_t             *packed_headers;        // contains packed headers. Used only along with PPT marker
+    int                 packed_headers_size;    // size in bytes of the packed headers
+    GetByteContext      packed_headers_stream;  // byte context corresponding to packed headers
+    uint16_t tp_idx;                    // Tile-part index
+    int coord[2][2];                    // border coordinates {{x0, x1}, {y0, y1}}
+} Jpeg2000Tile;
+
+typedef struct Jpeg2000DecoderContext {
+    AVClass         *class;
+    AVCodecContext  *avctx;
+    GetByteContext  g;
+
+    int             width, height;
+    int             image_offset_x, image_offset_y;
+    int             tile_offset_x, tile_offset_y;
+    uint8_t         cbps[4];    // bits per sample in particular components
+    uint8_t         sgnd[4];    // if a component is signed
+    uint8_t         properties[4];
+
+    uint8_t         has_ppm;
+    uint8_t         *packed_headers; // contains packed headers. Used only along with PPM marker
+    int             packed_headers_size;
+    GetByteContext  packed_headers_stream;
+    uint8_t         in_tile_headers;
+
+    int             cdx[4], cdy[4];
+    int             precision;
+    int             ncomponents;
+    int             colour_space;
+    uint32_t        palette[256];
+    int8_t          pal8;
+    int             cdef[4];
+    int             tile_width, tile_height;
+    unsigned        numXtiles, numYtiles;
+    int             maxtilelen;
+    AVRational      sar;
+
+    Jpeg2000CodingStyle codsty[4];
+    Jpeg2000QuantStyle  qntsty[4];
+    Jpeg2000POC         poc;
+    uint8_t             roi_shift[4];
+
+    int             bit_index;
+
+    int             curtileno;
+
+    Jpeg2000Tile    *tile;
+    Jpeg2000DSPContext dsp;
+
+    // options parameters
+    int             reduction_factor;
+} Jpeg2000DecoderContext;
+
 /* misc tools */
 static inline int ff_jpeg2000_ceildivpow2(int a, int b)
 {
@@ -286,6 +374,8 @@ void ff_jpeg2000_reinit(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty);
 
 void ff_jpeg2000_cleanup(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty);
 
+int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s);
+
 static inline int needs_termination(int style, int passno) {
     if (style & JPEG2000_CBLK_BYPASS) {
         int type = passno % 3;
diff --git a/ffmpeg/libavcodec/jpeg2000dec.c b/ffmpeg/libavcodec/jpeg2000dec.c
index c2b81ec..80db484 100644
--- a/ffmpeg/libavcodec/jpeg2000dec.c
+++ b/ffmpeg/libavcodec/jpeg2000dec.c
@@ -51,93 +51,6 @@
 #define HAD_COC 0x01
 #define HAD_QCC 0x02
 
-#define MAX_POCS 32
-
-typedef struct Jpeg2000POCEntry {
-    uint16_t LYEpoc;
-    uint16_t CSpoc;
-    uint16_t CEpoc;
-    uint8_t RSpoc;
-    uint8_t REpoc;
-    uint8_t Ppoc;
-} Jpeg2000POCEntry;
-
-typedef struct Jpeg2000POC {
-    Jpeg2000POCEntry poc[MAX_POCS];
-    int nb_poc;
-    int is_default;
-} Jpeg2000POC;
-
-typedef struct Jpeg2000TilePart {
-    uint8_t tile_index;                 // Tile index who refers the tile-part
-    const uint8_t *tp_end;
-    GetByteContext header_tpg;          // bit stream of header if PPM header is used
-    GetByteContext tpg;                 // bit stream in tile-part
-} Jpeg2000TilePart;
-
-/* RMK: For JPEG2000 DCINEMA 3 tile-parts in a tile
- * one per component, so tile_part elements have a size of 3 */
-typedef struct Jpeg2000Tile {
-    Jpeg2000Component   *comp;
-    uint8_t             properties[4];
-    Jpeg2000CodingStyle codsty[4];
-    Jpeg2000QuantStyle  qntsty[4];
-    Jpeg2000POC         poc;
-    Jpeg2000TilePart    tile_part[32];
-    uint8_t             has_ppt;                // whether this tile has a ppt marker
-    uint8_t             *packed_headers;        // contains packed headers. Used only along with PPT marker
-    int                 packed_headers_size;    // size in bytes of the packed headers
-    GetByteContext      packed_headers_stream;  // byte context corresponding to packed headers
-    uint16_t tp_idx;                    // Tile-part index
-    int coord[2][2];                    // border coordinates {{x0, x1}, {y0, y1}}
-} Jpeg2000Tile;
-
-typedef struct Jpeg2000DecoderContext {
-    AVClass         *class;
-    AVCodecContext  *avctx;
-    GetByteContext  g;
-
-    int             width, height;
-    int             image_offset_x, image_offset_y;
-    int             tile_offset_x, tile_offset_y;
-    uint8_t         cbps[4];    // bits per sample in particular components
-    uint8_t         sgnd[4];    // if a component is signed
-    uint8_t         properties[4];
-
-    uint8_t         has_ppm;
-    uint8_t         *packed_headers; // contains packed headers. Used only along with PPM marker
-    int             packed_headers_size;
-    GetByteContext  packed_headers_stream;
-    uint8_t         in_tile_headers;
-
-    int             cdx[4], cdy[4];
-    int             precision;
-    int             ncomponents;
-    int             colour_space;
-    uint32_t        palette[256];
-    int8_t          pal8;
-    int             cdef[4];
-    int             tile_width, tile_height;
-    unsigned        numXtiles, numYtiles;
-    int             maxtilelen;
-    AVRational      sar;
-
-    Jpeg2000CodingStyle codsty[4];
-    Jpeg2000QuantStyle  qntsty[4];
-    Jpeg2000POC         poc;
-    uint8_t             roi_shift[4];
-
-    int             bit_index;
-
-    int             curtileno;
-
-    Jpeg2000Tile    *tile;
-    Jpeg2000DSPContext dsp;
-
-    /*options parameters*/
-    int             reduction_factor;
-} Jpeg2000DecoderContext;
-
 /* get_bits functions for JPEG2000 packet bitstream
  * It is a get_bit function with a bit-stuffing routine. If the value of the
  * byte is 0xFF, the next byte includes an extra zero bit stuffed into the MSB.
@@ -2134,7 +2047,7 @@ static void jpeg2000_dec_cleanup(Jpeg2000DecoderContext *s)
     s->ncomponents = 0;
 }
 
-static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s)
+int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s)
 {
     Jpeg2000CodingStyle *codsty = s->codsty;
     Jpeg2000QuantStyle *qntsty  = s->qntsty;
diff --git a/ffmpeg/libavformat/mxf.h b/ffmpeg/libavformat/mxf.h
index 2561605..7dd1681 100644
--- a/ffmpeg/libavformat/mxf.h
+++ b/ffmpeg/libavformat/mxf.h
@@ -55,6 +55,7 @@ enum MXFMetadataSetType {
     SoundfieldGroupLabelSubDescriptor,
     GroupOfSoundfieldGroupsLabelSubDescriptor,
     FFV1SubDescriptor,
+    JPEG2000SubDescriptor,
 };
 
 enum MXFFrameLayout {
diff --git a/ffmpeg/libavformat/mxfenc.c b/ffmpeg/libavformat/mxfenc.c
index a29d678..aa7dbd7 100644
--- a/ffmpeg/libavformat/mxfenc.c
+++ b/ffmpeg/libavformat/mxfenc.c
@@ -48,8 +48,10 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/time_internal.h"
 #include "libavcodec/avcodec.h"
+#include "libavcodec/bytestream.h"
 #include "libavcodec/golomb.h"
 #include "libavcodec/h264.h"
+#include "libavcodec/jpeg2000.h"
 #include "libavcodec/packet_internal.h"
 #include "libavcodec/startcode.h"
 #include "avformat.h"
@@ -102,6 +104,16 @@ typedef struct MXFStreamContext {
     int b_picture_count;     ///< maximum number of consecutive b pictures, used in mpeg-2 descriptor
     int low_delay;           ///< low delay, used in mpeg-2 descriptor
     int avc_intra;
+    uint16_t j2k_rsiz;       ///< j2k required decoder capabilities (Rsiz)
+    uint32_t j2k_xsiz;       ///< j2k widht of the reference grid (Xsiz)
+    uint32_t j2k_ysiz;       ///< j2k height of the reference grid (Ysiz)
+    uint32_t j2k_x0siz;      ///< j2k horizontal offset from the origin of the reference grid to the left side of the image (X0siz)
+    uint32_t j2k_y0siz;      ///< j2k vertical offset from the origin of the reference grid to the left side of the image (Y0siz)
+    uint32_t j2k_xtsiz;      ///< j2k width of one reference tile with respect to the reference grid (XTsiz)
+    uint32_t j2k_ytsiz;      ///< j2k height of one reference tile with respect to the reference grid (YTsiz)
+    uint32_t j2k_xt0siz;     ///< j2k horizontal offset from the origin of the reference grid to the left side of the first tile (XT0siz)
+    uint32_t j2k_yt0siz;     ///< j2k vertical offset from the origin of the reference grid to the left side of the first tile (YT0siz)
+    uint8_t  j2k_comp_desc[12]; ///< j2k components descriptor (Ssiz(i), XRsiz(i), YRsiz(i))
 } MXFStreamContext;
 
 typedef struct MXFContainerEssenceEntry {
@@ -390,6 +402,20 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = {
     { 0x8302, FF_MXF_MasteringDisplayWhitePointChromaticity },
     { 0x8303, FF_MXF_MasteringDisplayMaximumLuminance },
     { 0x8304, FF_MXF_MasteringDisplayMinimumLuminance },
+    // ff_mxf_jpeg2000_local_tags
+    { 0x8400, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x04,0x06,0x10,0x00,0x00}}, /* Sub Descriptors / Opt Ordered array of strong references to sub descriptor sets */
+    { 0x8401, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x01,0x00,0x00,0x00}}, /* Rsiz: An enumerated value that defines the decoder capabilities */
+    { 0x8402, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x02,0x00,0x00,0x00}}, /* Xsiz: Width of the reference grid */
+    { 0x8403, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x03,0x00,0x00,0x00}}, /* Ysiz: Height of the reference grid */
+    { 0x8404, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x04,0x00,0x00,0x00}}, /* X0siz: Horizontal offset from the origin of the reference grid to the left side of the image area */
+    { 0x8405, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x05,0x00,0x00,0x00}}, /* Y0siz: Vertical offset from the origin of the reference grid to the left side of the image area */
+    { 0x8406, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x06,0x00,0x00,0x00}}, /* XTsiz: Width of one reference tile with respect to the reference grid */
+    { 0x8407, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x07,0x00,0x00,0x00}}, /* YTsiz: Height of one reference tile with respect to the reference grid */
+    { 0x8408, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x08,0x00,0x00,0x00}}, /* XT0siz: Horizontal offset from the origin of the reference grid to the left side of the first tile */
+    { 0x8409, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x09,0x00,0x00,0x00}}, /* YT0siz: Vertical offset from the origin of the reference grid to the left side of the first tile */
+    { 0x840A, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x0A,0x00,0x00,0x00}}, /* Csiz: The number of components in the picture */
+    { 0x840B, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x0B,0x00,0x00,0x00}}, /* Ssizi, XRSizi, YRSizi: Array of picture components where each component comprises 3 bytes named Ssizi, XRSizi, YRSizi.  The array of 3-byte groups is preceded by the array header comprising a 4-byte value of the number of components followed by a 4-byte value of 3. */
+    { 0x840C, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x0E,0x00,0x00,0x00}}, /* The nature and order of the image components in the compressed domain as carried in the J2C codestream. */
 };
 
 #define MXF_NUM_TAGS FF_ARRAY_ELEMS(mxf_local_tag_batch)
@@ -526,7 +552,7 @@ static void mxf_write_primer_pack(AVFormatContext *s)
     MXFContext *mxf = s->priv_data;
     AVIOContext *pb = s->pb;
     int local_tag_number = MXF_NUM_TAGS, i;
-    int will_have_avc_tags = 0, will_have_mastering_tags = 0;
+    int will_have_avc_tags = 0, will_have_mastering_tags = 0, will_have_jpeg2000_tags = 0;
 
     for (i = 0; i < s->nb_streams; i++) {
         MXFStreamContext *sc = s->streams[i]->priv_data;
@@ -536,6 +562,9 @@ static void mxf_write_primer_pack(AVFormatContext *s)
         if (av_stream_get_side_data(s->streams[i], AV_PKT_DATA_MASTERING_DISPLAY_METADATA, NULL)) {
             will_have_mastering_tags = 1;
         }
+        if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_JPEG2000){
+            will_have_jpeg2000_tags = 1;
+        }
     }
 
     if (!mxf->store_user_comments) {
@@ -558,6 +587,22 @@ static void mxf_write_primer_pack(AVFormatContext *s)
         mxf_mark_tag_unused(mxf, 0x8304);
     }
 
+    if (!will_have_jpeg2000_tags) {
+        mxf_mark_tag_unused(mxf, 0x8400);
+        mxf_mark_tag_unused(mxf, 0x8401);
+        mxf_mark_tag_unused(mxf, 0x8402);
+        mxf_mark_tag_unused(mxf, 0x8403);
+        mxf_mark_tag_unused(mxf, 0x8404);
+        mxf_mark_tag_unused(mxf, 0x8405);
+        mxf_mark_tag_unused(mxf, 0x8406);
+        mxf_mark_tag_unused(mxf, 0x8407);
+        mxf_mark_tag_unused(mxf, 0x8408);
+        mxf_mark_tag_unused(mxf, 0x8409);
+        mxf_mark_tag_unused(mxf, 0x840A);
+        mxf_mark_tag_unused(mxf, 0x840B);
+        mxf_mark_tag_unused(mxf, 0x840C);
+    }
+
     for (i = 0; i < MXF_NUM_TAGS; i++) {
         if (mxf->unused_tags[i]) {
             local_tag_number--;
@@ -1095,8 +1140,8 @@ static const UID mxf_wav_descriptor_key       = { 0x06,0x0E,0x2B,0x34,0x02,0x53,
 static const UID mxf_aes3_descriptor_key      = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 };
 static const UID mxf_cdci_descriptor_key      = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x28,0x00 };
 static const UID mxf_generic_sound_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x42,0x00 };
-
 static const UID mxf_avc_subdescriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x6E,0x00 };
+static const UID mxf_jpeg2000_subdescriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x5A,0x00};
 
 static inline uint16_t rescale_mastering_chroma(AVRational q)
 {
@@ -1365,6 +1410,66 @@ static void mxf_write_avc_subdesc(AVFormatContext *s, AVStream *st)
     mxf_update_klv_size(s->pb, pos);
 }
 
+static void mxf_write_jpeg2000_subdesc(AVFormatContext *s, AVStream *st)
+{
+    MXFStreamContext *sc = st->priv_data;
+    AVIOContext *pb = s->pb;
+    int64_t pos;
+    int component_count = av_pix_fmt_count_planes(st->codecpar->format);
+    int comp = 0;
+
+    /* JPEG2000 subdescriptor key */
+    avio_write(pb, mxf_jpeg2000_subdescriptor_key, 16);
+    klv_encode_ber4_length(pb, 0);
+    pos = avio_tell(pb);
+
+    mxf_write_local_tag(s, 16, 0x3C0A);
+    mxf_write_uuid(pb, JPEG2000SubDescriptor, 0);
+
+    /* Value defining the decoder capabilities (rsiz) */
+    mxf_write_local_tag(s, 2, 0x8401);
+    avio_wb16(pb, sc->j2k_rsiz);
+    /* Width of the JPEG2000 reference grid (Xsiz) */
+    mxf_write_local_tag(s, 4, 0x8402);
+    avio_wb32(pb, st->codecpar->width);
+    /* Height of the JPEG2000 reference grid (Ysiz) */
+    mxf_write_local_tag(s, 4, 0x8403);
+    avio_wb32(pb, st->codecpar->height);
+    /* Horizontal offset from the reference grid origin to the left side of the image area (X0siz) */
+    mxf_write_local_tag(s, 4, 0x8404);
+    avio_wb32(pb, sc->j2k_x0siz);
+    /* Vertical offset from the reference grid origin to the left side of the image area (Y0siz) */
+    mxf_write_local_tag(s, 4, 0x8405);
+    avio_wb32(pb, sc->j2k_y0siz);
+    /* Width of one reference tile with respect to the reference grid (XTsiz) */
+    mxf_write_local_tag(s, 4, 0x8406);
+    avio_wb32(pb, sc->j2k_xtsiz);
+    /* Height of one reference tile with respect to the reference grid (YTsiz) */
+    mxf_write_local_tag(s, 4, 0x8407);
+    avio_wb32(pb, sc->j2k_ytsiz);
+    /* Horizontal offset from the origin of the reference grid to the left side of the first tile (XT0siz) */
+    mxf_write_local_tag(s, 4, 0x8408);
+    avio_wb32(pb, sc->j2k_xt0siz);
+    /* Vertical offset from the origin of the reference grid to the left side of the first tile (YT0siz) */
+    mxf_write_local_tag(s, 4, 0x8409);
+    avio_wb32(pb, sc->j2k_yt0siz);
+    /* Image components number (Csiz) */
+    mxf_write_local_tag(s, 2, 0x840A);
+    avio_wb16(pb, component_count);
+    /* Array of picture components where each component comprises 3 bytes named Ssiz(i) (Pixel bitdepth - 1),
+       XRSiz(i) (Horizontal sampling), YRSiz(i) (Vertical sampling). The array of 3-byte groups is preceded
+       by the array header comprising a 4-byte value of the number of components followed by a 4-byte
+       value of 3. */
+    mxf_write_local_tag(s, 8 + 3*component_count, 0x840B);
+    avio_wb32(pb, component_count);
+    avio_wb32(pb, 3);
+    for ( comp = 0; comp < component_count; comp++ ) {
+        avio_write(pb, &sc->j2k_comp_desc[3*comp] , 3);
+    }
+
+    mxf_update_klv_size(pb, pos);
+}
+
 static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)
 {
     int64_t pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key);
@@ -1373,6 +1478,9 @@ static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)
     if (st->codecpar->codec_id == AV_CODEC_ID_H264) {
         mxf_write_avc_subdesc(s, st);
     }
+    if (st->codecpar->codec_id == AV_CODEC_ID_JPEG2000) {
+         mxf_write_jpeg2000_subdesc(s, st);
+    }
 }
 
 static void mxf_write_h264_desc(AVFormatContext *s, AVStream *st)
@@ -2113,6 +2221,58 @@ static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt
     return 1;
 }
 
+static int mxf_parse_jpeg2000_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt)
+{
+    MXFContext *mxf = s->priv_data;
+    MXFStreamContext *sc = st->priv_data;
+    int component_count = av_pix_fmt_count_planes(st->codecpar->format);
+    Jpeg2000DecoderContext jpeg2000ctx;
+    AVCodecContext avctx;
+    GetByteContext *g = &(jpeg2000ctx.g);
+    uint32_t j2k_ncomponents;
+    int comp;
+
+    if (mxf->header_written)
+        return 1;
+  
+    avctx.max_pixels = INT_MAX;
+    jpeg2000ctx.reduction_factor = 0;
+    jpeg2000ctx.avctx = &avctx;
+    bytestream2_init(g,pkt->data,pkt->size);
+    while (bytestream2_get_bytes_left(g) >= 3 && bytestream2_peek_be16(g) != JPEG2000_SOC)
+        bytestream2_skip(g, 1);
+
+    if (bytestream2_get_be16u(g) != JPEG2000_SOC) {
+        av_log(s, AV_LOG_ERROR, "Invalid J2K codestream: SOC marker not present.\n");
+        return AVERROR(EINVAL);
+    }
+
+    jpeg2000_read_main_headers(&jpeg2000ctx);
+    sc->j2k_rsiz = jpeg2000ctx.avctx->profile; // Rsiz
+    sc->j2k_xsiz = jpeg2000ctx.width; // Xsiz
+    sc->j2k_ysiz = jpeg2000ctx.height; // Ysiz
+    sc->j2k_x0siz = jpeg2000ctx.image_offset_x; // X0siz
+    sc->j2k_y0siz = jpeg2000ctx.image_offset_y; // Y0siz
+    sc->j2k_xtsiz = jpeg2000ctx.tile_width; // XTsiz
+    sc->j2k_ytsiz = jpeg2000ctx.tile_height; // YTsiz
+    sc->j2k_xt0siz = jpeg2000ctx.tile_offset_x; // XT0siz
+    sc->j2k_yt0siz = jpeg2000ctx.tile_offset_y; // YT0siz
+    j2k_ncomponents = jpeg2000ctx.ncomponents; // Csiz
+    if (j2k_ncomponents != component_count) {
+        av_log(s, AV_LOG_ERROR, "Incoherence about components image number.\n");
+        return AVERROR(EINVAL);
+    }
+    for (comp = 0; comp < j2k_ncomponents; comp++) {
+        sc->j2k_comp_desc[comp*j2k_ncomponents] = (jpeg2000ctx.sgnd[comp]<<7)+jpeg2000ctx.cbps[comp]-1; // Ssiz(i)
+        sc->j2k_comp_desc[comp*j2k_ncomponents+1] = jpeg2000ctx.cdx[comp]; // XRsiz(i)
+        sc->j2k_comp_desc[comp*j2k_ncomponents+2] = jpeg2000ctx.cdy[comp]; // YRsiz(i))
+    }
+
+    sc->frame_size = pkt->size;
+
+    return 1;
+}
+
 static const struct {
     const UID container_ul;
     const UID codec_ul;
@@ -2958,6 +3118,11 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
             av_log(s, AV_LOG_ERROR, "could not get h264 profile\n");
             return -1;
         }
+    } else if (st->codecpar->codec_id == AV_CODEC_ID_JPEG2000) {
+        if (!mxf_parse_jpeg2000_frame(s, st, pkt)) {
+            av_log(s, AV_LOG_ERROR, "could not get jpeg2000 profile\n");
+            return -1;
+        }
     }
 
     if (mxf->cbr_index) {
-- 
2.34.1