--- Begin Message ---
Signed-off-by: Cedric Le Barz <cleb...@ektacom.com>
---
ffmpeg/libavformat/mxf.h | 1 +
ffmpeg/libavformat/mxfenc.c | 169 +++++++++++++++++++++++++++++++++++-
2 files changed, 168 insertions(+), 2 deletions(-)
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..909682a 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_cap; ///< j2k required decoder capabilities
+ uint32_t j2k_xsiz; ///< j2k widht of the reference grid
+ uint32_t j2k_ysiz; ///< j2k height of the reference grid
+ uint32_t j2k_x0siz; ///< j2k horizontal offset from the origin of the
reference grid to the left side of the image
+ uint32_t j2k_y0siz; ///< j2k vertical offset from the origin of the
reference grid to the left side of the image
+ uint32_t j2k_xtsiz; ///< j2k width of one reference tile with respect
to the reference grid
+ uint32_t j2k_ytsiz; ///< j2k height of one reference tile with
respect to the reference grid
+ uint32_t j2k_xt0siz; ///< j2k horizontal offset from the origin of the
reference grid to the left side of the first tile
+ uint32_t j2k_yt0siz; ///< j2k vertical offset from the origin of the
reference grid to the left side of the first tile
+ uint8_t j2k_comp_desc[12]; ///< j2k components descriptor
} 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}},
/* 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}},
/* Width of the reference grid */
+ { 0x8403,
{0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x03,0x00,0x00,0x00}},
/* Height of the reference grid */
+ { 0x8404,
{0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x04,0x00,0x00,0x00}},
/* 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}},
/* 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}},
/* 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}},
/* 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}},
/* 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}},
/* 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}},
/* The number of components in the picture */
+ { 0x840B,
{0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x0B,0x00,0x00,0x00}},
/* 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 */
+ mxf_write_local_tag(s, 2, 0x8401);
+ avio_wb16(pb, sc->j2k_cap);
+ /* Width of the JPEG2000 reference grid */
+ mxf_write_local_tag(s, 4, 0x8402);
+ avio_wb32(pb, st->codecpar->width);
+ /* Height of the JPEG2000 reference grid */
+ 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 */
+ 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 */
+ mxf_write_local_tag(s, 4, 0x8405);
+ avio_wb32(pb, sc->j2k_y0siz);
+ /* Width of one reference tile with respect to the reference grid */
+ mxf_write_local_tag(s, 4, 0x8406);
+ avio_wb32(pb, sc->j2k_xtsiz);
+ /* Height of one reference tile with respect to the reference grid */
+ 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 */
+ 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 */
+ mxf_write_local_tag(s, 4, 0x8409);
+ avio_wb32(pb, sc->j2k_yt0siz);
+ /* Image components number */
+ 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);
+ GetByteContext g;
+ uint32_t j2k_ncomponents;
+ int comp;
+
+ if (mxf->header_written)
+ return 1;
+
+ 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, "SOC marker not present\n");
+ return 0;
+ }
+
+ /* Extract usefull size infromation from the SIZ marker */
+ if (bytestream2_get_be16u(&g) != JPEG2000_SIZ) {
+ av_log(s, AV_LOG_ERROR, "SIZ marker not present\n");
+ return 0;
+ }
+ bytestream2_skip(&g, 2); // Skip Lsiz
+ sc->j2k_cap = bytestream2_get_be16u(&g);
+ sc->j2k_xsiz = bytestream2_get_be32u(&g);
+ sc->j2k_ysiz = bytestream2_get_be32u(&g);
+ sc->j2k_x0siz = bytestream2_get_be32u(&g);
+ sc->j2k_y0siz = bytestream2_get_be32u(&g);
+ sc->j2k_xtsiz = bytestream2_get_be32u(&g);
+ sc->j2k_ytsiz = bytestream2_get_be32u(&g);
+ sc->j2k_xt0siz = bytestream2_get_be32u(&g);
+ sc->j2k_yt0siz = bytestream2_get_be32u(&g);
+ j2k_ncomponents = bytestream2_get_be16u(&g);
+ if (j2k_ncomponents != component_count) {
+ av_log(s, AV_LOG_ERROR, "Incoherence about components image
number.\n");
+ }
+ for (comp = 0; comp < j2k_ncomponents; comp++) {
+ sc->j2k_comp_desc[comp*j2k_ncomponents] = bytestream2_get_byteu(&g);
// Bitdepth for each component
+ sc->j2k_comp_desc[comp*j2k_ncomponents+1] = bytestream2_get_byteu(&g);
// Horizontal sampling for each component
+ sc->j2k_comp_desc[comp*j2k_ncomponents+2] = bytestream2_get_byteu(&g);
// Vertical sampling for each component
+ }
+
+ 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
--- End Message ---